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.
- fast_clean/__init__.py +3 -0
- fast_clean/broker.py +123 -0
- fast_clean/container.py +235 -0
- fast_clean/contrib/__init__.py +3 -0
- fast_clean/contrib/healthcheck/__init__.py +3 -0
- fast_clean/contrib/healthcheck/router.py +17 -0
- fast_clean/db.py +179 -0
- fast_clean/depends.py +255 -0
- fast_clean/enums.py +39 -0
- fast_clean/exceptions.py +281 -0
- fast_clean/loggers.py +26 -0
- fast_clean/middleware.py +20 -0
- fast_clean/models.py +33 -0
- fast_clean/py.typed +0 -0
- fast_clean/redis.py +23 -0
- fast_clean/repositories/__init__.py +30 -0
- fast_clean/repositories/cache/__init__.py +83 -0
- fast_clean/repositories/cache/in_memory.py +62 -0
- fast_clean/repositories/cache/redis.py +58 -0
- fast_clean/repositories/crud/__init__.py +149 -0
- fast_clean/repositories/crud/db.py +559 -0
- fast_clean/repositories/crud/in_memory.py +369 -0
- fast_clean/repositories/crud/type_vars.py +35 -0
- fast_clean/repositories/settings/__init__.py +52 -0
- fast_clean/repositories/settings/enums.py +16 -0
- fast_clean/repositories/settings/env.py +55 -0
- fast_clean/repositories/settings/exceptions.py +13 -0
- fast_clean/repositories/settings/type_vars.py +9 -0
- fast_clean/repositories/storage/__init__.py +114 -0
- fast_clean/repositories/storage/enums.py +20 -0
- fast_clean/repositories/storage/local.py +118 -0
- fast_clean/repositories/storage/reader.py +122 -0
- fast_clean/repositories/storage/s3.py +118 -0
- fast_clean/repositories/storage/schemas.py +31 -0
- fast_clean/schemas/__init__.py +25 -0
- fast_clean/schemas/exceptions.py +32 -0
- fast_clean/schemas/pagination.py +65 -0
- fast_clean/schemas/repository.py +43 -0
- fast_clean/schemas/request_response.py +36 -0
- fast_clean/schemas/status_response.py +13 -0
- fast_clean/services/__init__.py +16 -0
- fast_clean/services/cryptography/__init__.py +57 -0
- fast_clean/services/cryptography/aes.py +120 -0
- fast_clean/services/cryptography/enums.py +20 -0
- fast_clean/services/lock.py +57 -0
- fast_clean/services/seed.py +91 -0
- fast_clean/services/transaction.py +40 -0
- fast_clean/settings.py +189 -0
- fast_clean/tools/__init__.py +6 -0
- fast_clean/tools/cryptography.py +56 -0
- fast_clean/tools/load_seed.py +31 -0
- fast_clean/use_cases.py +38 -0
- fast_clean/utils/__init__.py +15 -0
- fast_clean/utils/process.py +31 -0
- fast_clean/utils/pydantic.py +23 -0
- fast_clean/utils/ssl_context.py +31 -0
- fast_clean/utils/string.py +28 -0
- fast_clean/utils/thread.py +21 -0
- fast_clean/utils/time.py +14 -0
- fast_clean/utils/type_converters.py +18 -0
- fast_clean/utils/typer.py +23 -0
- fast_clean-0.4.0.dist-info/METADATA +38 -0
- fast_clean-0.4.0.dist-info/RECORD +65 -0
- fast_clean-0.4.0.dist-info/WHEEL +5 -0
- fast_clean-0.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
"""
|
2
|
+
Модуль запуска тяжелых операций в ProcessPoolExecutor.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import asyncio
|
6
|
+
import multiprocessing as mp
|
7
|
+
from concurrent.futures import ProcessPoolExecutor
|
8
|
+
from functools import partial
|
9
|
+
from typing import Callable, TypeVar
|
10
|
+
|
11
|
+
from typing_extensions import ParamSpec
|
12
|
+
|
13
|
+
P = ParamSpec('P')
|
14
|
+
R = TypeVar('R')
|
15
|
+
|
16
|
+
|
17
|
+
process_pool: ProcessPoolExecutor | None = None
|
18
|
+
|
19
|
+
|
20
|
+
async def run_in_processpool(fn: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R:
|
21
|
+
"""
|
22
|
+
Запуск функции в отдельном процессе.
|
23
|
+
|
24
|
+
Используем fork в связи с https://github.com/python/cpython/issues/94765.
|
25
|
+
"""
|
26
|
+
global process_pool
|
27
|
+
if process_pool is None:
|
28
|
+
process_pool = ProcessPoolExecutor(mp_context=mp.get_context('fork'))
|
29
|
+
kwargs_fn = partial(fn, *args, **kwargs)
|
30
|
+
loop = asyncio.get_running_loop()
|
31
|
+
return await loop.run_in_executor(process_pool, kwargs_fn)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""
|
2
|
+
Модуль, содержащий вспомогательные функции для работы с Pydantic.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import importlib
|
6
|
+
from collections.abc import Iterable
|
7
|
+
|
8
|
+
from pydantic import BaseModel
|
9
|
+
|
10
|
+
|
11
|
+
def rebuild_schemas(modules: Iterable[str]) -> None:
|
12
|
+
"""
|
13
|
+
Перестраиваем не полностью объявленные схемы из-за циклических зависимостей.
|
14
|
+
|
15
|
+
https://docs.pydantic.dev/2.10/concepts/models/#rebuilding-model-schema
|
16
|
+
"""
|
17
|
+
schemas: dict[str, type[BaseModel]] = {}
|
18
|
+
for module in modules:
|
19
|
+
for key, obj in importlib.import_module(module).__dict__.items():
|
20
|
+
if isinstance(obj, type) and issubclass(obj, BaseModel) and obj is not BaseModel:
|
21
|
+
schemas[key] = obj
|
22
|
+
for schema in schemas.values():
|
23
|
+
schema.model_rebuild(_types_namespace=schemas)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
"""
|
2
|
+
Модуль для создания SSL контекста.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import ssl
|
6
|
+
from typing import TypeAlias
|
7
|
+
|
8
|
+
from pydantic import BaseModel
|
9
|
+
|
10
|
+
StrOrBytesPath: TypeAlias = str | bytes # stable
|
11
|
+
|
12
|
+
|
13
|
+
class CertificateSchema(BaseModel):
|
14
|
+
"""
|
15
|
+
Схема необходимых файлов для создания SSL контекста.
|
16
|
+
"""
|
17
|
+
|
18
|
+
ca_file: StrOrBytesPath
|
19
|
+
cert_file: StrOrBytesPath
|
20
|
+
key_file: StrOrBytesPath
|
21
|
+
password: str | None = None
|
22
|
+
|
23
|
+
|
24
|
+
def make_ssl_context(params: CertificateSchema, check_hostname: bool = False) -> ssl.SSLContext:
|
25
|
+
"""
|
26
|
+
Создаем SSL контекст.
|
27
|
+
"""
|
28
|
+
ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=params.ca_file)
|
29
|
+
ssl_context.load_cert_chain(certfile=params.cert_file, keyfile=params.key_file, password=params.password)
|
30
|
+
ssl_context.check_hostname = check_hostname
|
31
|
+
return ssl_context
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"""
|
2
|
+
Модуль для работы со строками.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import base64
|
6
|
+
import string
|
7
|
+
from random import choice
|
8
|
+
|
9
|
+
|
10
|
+
def make_random_string(size: int) -> str:
|
11
|
+
"""
|
12
|
+
Создаем случайную строку.
|
13
|
+
"""
|
14
|
+
return ''.join(choice(string.ascii_letters + string.digits) for _ in range(size))
|
15
|
+
|
16
|
+
|
17
|
+
def encode_base64(raw_value: str) -> str:
|
18
|
+
"""
|
19
|
+
Кодируем строку в base64.
|
20
|
+
"""
|
21
|
+
return base64.b64encode(raw_value.encode()).decode()
|
22
|
+
|
23
|
+
|
24
|
+
def decode_base64(value: str) -> str:
|
25
|
+
"""
|
26
|
+
Декодируем строку из base64.
|
27
|
+
"""
|
28
|
+
return base64.b64decode(value).decode()
|
@@ -0,0 +1,21 @@
|
|
1
|
+
"""
|
2
|
+
Модель запуска тяжелых операций в ThreadPoolExecutor.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import asyncio
|
6
|
+
from functools import partial
|
7
|
+
from typing import Callable, TypeVar
|
8
|
+
|
9
|
+
from typing_extensions import ParamSpec
|
10
|
+
|
11
|
+
R = TypeVar('R')
|
12
|
+
P = ParamSpec('P')
|
13
|
+
|
14
|
+
|
15
|
+
async def run_in_threadpool(fn: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R:
|
16
|
+
"""
|
17
|
+
Запуск функции в отдельном потоке.
|
18
|
+
"""
|
19
|
+
kwargs_fn = partial(fn, *args, **kwargs)
|
20
|
+
loop = asyncio.get_running_loop()
|
21
|
+
return await loop.run_in_executor(None, kwargs_fn)
|
fast_clean/utils/time.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
"""
|
2
|
+
Модуль, содержащий функции для преобразования типов.
|
3
|
+
"""
|
4
|
+
|
5
|
+
true_set = {'yes', 'true', 't', 'y', '1'}
|
6
|
+
false_set = {'no', 'false', 'f', 'n', '0'}
|
7
|
+
|
8
|
+
|
9
|
+
def str_to_bool(value: str) -> bool:
|
10
|
+
"""
|
11
|
+
Преобразуем строку к логическом значению.
|
12
|
+
"""
|
13
|
+
value = value.lower()
|
14
|
+
if value in true_set:
|
15
|
+
return True
|
16
|
+
if value in false_set:
|
17
|
+
return False
|
18
|
+
raise ValueError('Expected "%s"' % '", "'.join(true_set | false_set))
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""
|
2
|
+
Модуль, содержащий вспомогательные функции для работы с Typer.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import asyncio
|
6
|
+
from collections.abc import Callable, Coroutine
|
7
|
+
from functools import wraps
|
8
|
+
from typing import Any, ParamSpec, TypeVar
|
9
|
+
|
10
|
+
Param = ParamSpec('Param')
|
11
|
+
RetType = TypeVar('RetType')
|
12
|
+
|
13
|
+
|
14
|
+
def typer_async(func: Callable[Param, Coroutine[Any, Any, RetType]]) -> Callable[Param, RetType]:
|
15
|
+
"""
|
16
|
+
Декоратор для асинхронного запуска Typer.
|
17
|
+
"""
|
18
|
+
|
19
|
+
@wraps(func)
|
20
|
+
def wrapper(*args: Param.args, **kwargs: Param.kwargs) -> RetType:
|
21
|
+
return asyncio.run(func(*args, **kwargs))
|
22
|
+
|
23
|
+
return wrapper
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: fast-clean
|
3
|
+
Version: 0.4.0
|
4
|
+
Summary: FastAPI Clean Architecture implementation
|
5
|
+
Author-email: Luferov Victor <luferovvs@yandex.ru>, Orlov Artem <squakrazv@yandex.ru>
|
6
|
+
Requires-Python: >=3.12
|
7
|
+
Description-Content-Type: text/markdown
|
8
|
+
Requires-Dist: aiofiles>=24.1.0
|
9
|
+
Requires-Dist: aiokafka>=0.12.0
|
10
|
+
Requires-Dist: cryptography>=44.0.1
|
11
|
+
Requires-Dist: fastapi>=0.115.8
|
12
|
+
Requires-Dist: fastapi-cache2[redis]>=0.2.2
|
13
|
+
Requires-Dist: faststream>=0.5.34
|
14
|
+
Requires-Dist: flatten-dict>=0.4.2
|
15
|
+
Requires-Dist: miniopy-async>=1.21.1
|
16
|
+
Requires-Dist: overrides>=7.7.0
|
17
|
+
Requires-Dist: psycopg>=3.2.4
|
18
|
+
Requires-Dist: pydantic>=2.10.6
|
19
|
+
Requires-Dist: pydantic-settings>=2.8.0
|
20
|
+
Requires-Dist: pyyaml>=6.0.2
|
21
|
+
Requires-Dist: sqlalchemy-utils>=0.41.2
|
22
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.38
|
23
|
+
Requires-Dist: stringcase>=1.2.0
|
24
|
+
Requires-Dist: typer>=0.15.1
|
25
|
+
|
26
|
+
# FastClean
|
27
|
+
|
28
|
+
FastAPI clean architecture implementation
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
## Contribution
|
33
|
+
|
34
|
+
```
|
35
|
+
git clone git@github.com:Luferov/fast-clean.git
|
36
|
+
uv sync --all-extras --dev
|
37
|
+
uv run pre-commit install
|
38
|
+
```
|
@@ -0,0 +1,65 @@
|
|
1
|
+
fast_clean/__init__.py,sha256=sT4tb75t5PXws8W_7wpA0jNtNxkWPFLAMrPlDGS7RHw,51
|
2
|
+
fast_clean/broker.py,sha256=CHnL4Jd6jF5gKgtUXi33j9QFG2EUM4uqhVqdLuxIrZs,4474
|
3
|
+
fast_clean/container.py,sha256=i7ZLZY_UN6ohGn-PT3RgAkzRPza3-DWRfgRdoaeMBWU,9562
|
4
|
+
fast_clean/db.py,sha256=d03D9cYHpq8iQ7ErAwZYggLhITmxD5feSr071kv0_x0,5507
|
5
|
+
fast_clean/depends.py,sha256=94mIIfXoY7X_lm0xrcd15QjrGkyr_QLF0Om5byJNuJ0,8824
|
6
|
+
fast_clean/enums.py,sha256=lPhC_2_r6YFby7Mq-9u_JSiuyZ0e57F2VxBfUwnBZ18,826
|
7
|
+
fast_clean/exceptions.py,sha256=Sp-k-a5z1Gedu0slzj1-rORnr4GP1FXDHKCKRaJq-7o,9485
|
8
|
+
fast_clean/loggers.py,sha256=hVvZSDMMxYnK-p_yyjd4R7SyHpmxQF3eKQEeMu9Q-jo,705
|
9
|
+
fast_clean/middleware.py,sha256=7iaA39ug85oOtSdQP8T3u8cX4KAAvDlfAlUg43_riR0,461
|
10
|
+
fast_clean/models.py,sha256=qnNUSwLf0gOW8C98PMIs6vTw7UP3-Nk-k6YoFvHstVM,880
|
11
|
+
fast_clean/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
+
fast_clean/redis.py,sha256=H_SLnDhY_ute8pYHdhIypUGlCwMcVfFA4S2j8vLUph0,578
|
13
|
+
fast_clean/settings.py,sha256=o460LZjXW0_WYe0QB9g0fTgch8dhkUq-6flAnf4LKM4,4715
|
14
|
+
fast_clean/use_cases.py,sha256=XzRqnS3LOkaadbL50-E9f7q3Bi5Yz4AOCHKh82AH0Mg,1384
|
15
|
+
fast_clean/contrib/__init__.py,sha256=AcFNyhc0QGsOnYvzQGanDN3QIAsKpn4d8RIj73F-sGc,63
|
16
|
+
fast_clean/contrib/healthcheck/__init__.py,sha256=p8hUCLdv2qGngTwAeTGIV4h_ZGDm9ZNWMrA5_k3Yi0E,106
|
17
|
+
fast_clean/contrib/healthcheck/router.py,sha256=6kyFuNqR5m3pB_fzerrZ7m7yvoqL_BiwkUMeLrxJVnE,408
|
18
|
+
fast_clean/repositories/__init__.py,sha256=IpETRNot2t6rI5qUtsyqinkloS2fhcqSVpB5-s1iUmY,1753
|
19
|
+
fast_clean/repositories/cache/__init__.py,sha256=9i3_AbUDt4HbPBRUfvNb2HqYGTDhZ6ZRRqz9jKE5o9c,2479
|
20
|
+
fast_clean/repositories/cache/in_memory.py,sha256=Hb68UrTmQozALcyLrmYPBIfJfi67NvsCTDe1RfqwBHQ,2259
|
21
|
+
fast_clean/repositories/cache/redis.py,sha256=UjrA2CXQtMfHTpowz6Ot952y73YjTEr6zJlBbWblaws,1908
|
22
|
+
fast_clean/repositories/crud/__init__.py,sha256=CrfjDlf0QLQXzX4GO7VkDf_qaZMPl1Pz9pXv9fCyWSU,4391
|
23
|
+
fast_clean/repositories/crud/db.py,sha256=OXQKBZ8pQGUgKiK_v1B0-HJIgXkS0EVwanXjDzjEwpc,23432
|
24
|
+
fast_clean/repositories/crud/in_memory.py,sha256=0JZJC4iYAnJLNYBDpwlekKj580Qao9X0HL1hpfP-x14,13407
|
25
|
+
fast_clean/repositories/crud/type_vars.py,sha256=YfSLmHAcjXLiR_uUevrAcT4_5dxc03ZLKPqRBN2aJG4,1306
|
26
|
+
fast_clean/repositories/settings/__init__.py,sha256=ZxrncvTDs8pNkhWSy2cxV3a8uElTnrM-b1-vq4ouJok,1485
|
27
|
+
fast_clean/repositories/settings/enums.py,sha256=coqZg6xe_mRFWeihBfnSkCByLuD0pT8Vv4g02tpBk-w,358
|
28
|
+
fast_clean/repositories/settings/env.py,sha256=maQttYENMJyTf4vnSXa4L3R6tKiLmb-d0Q5VS-r9ZuE,2153
|
29
|
+
fast_clean/repositories/settings/exceptions.py,sha256=SKU45z-ahPzI_G6k4A9twupx1v3GaXDj2pbFkg3YgFE,348
|
30
|
+
fast_clean/repositories/settings/type_vars.py,sha256=_Oe8x4JwwrN9WOVjLA05BN6gv7cBcBmq2YR2ZI4Hz5w,197
|
31
|
+
fast_clean/repositories/storage/__init__.py,sha256=mP_2NTx_Ec19WCmxecJsbjvNjhy8Oj8001lJC-BTGB8,3582
|
32
|
+
fast_clean/repositories/storage/enums.py,sha256=bS4L63aEXNaGnJql8A1jmsK4KY916cWnzTW5p_PyLmg,375
|
33
|
+
fast_clean/repositories/storage/local.py,sha256=s5REPU7xczvzin13sKyZtFdiocrgAMk8bnDIbJ90KT4,4270
|
34
|
+
fast_clean/repositories/storage/reader.py,sha256=yAxj51ITWJf0u-KGC3DJ0iTB3pDI1p9ixi_h0ZcWoZ4,3299
|
35
|
+
fast_clean/repositories/storage/s3.py,sha256=GcJ0qo6RgMSCIOKdafSwH4kz1YHc_2cOYuvgxT81yvI,4302
|
36
|
+
fast_clean/repositories/storage/schemas.py,sha256=etlogfK_1uUZPQjHWQN6LWy6-8YY2Sago3Zbf6p0KcQ,623
|
37
|
+
fast_clean/schemas/__init__.py,sha256=u7U2j-QURCEIL_Gg3cQyp3oCbsT497lD3X54nqWDfzQ,1361
|
38
|
+
fast_clean/schemas/exceptions.py,sha256=E7G9jv4G82Ede7OQ3619vPGwEywc7tKmXW6EolOGRFQ,723
|
39
|
+
fast_clean/schemas/pagination.py,sha256=GEQ-Tbhx6xkMMXhDNWrTEhPv8IdnAOJxH2P1tscmn60,1384
|
40
|
+
fast_clean/schemas/repository.py,sha256=up4-c7irCRm73Xsq0jMu5pot1xMDOuNRNNopId0-Zn8,889
|
41
|
+
fast_clean/schemas/request_response.py,sha256=i4HTpjelWl4DxJ1sQaeanTWB_PThlhVJRhtMMGqRAiQ,693
|
42
|
+
fast_clean/schemas/status_response.py,sha256=mASZRCNtKJnDbmhr8_pBytkE_3NguyTIFqO4aw-nNEQ,269
|
43
|
+
fast_clean/services/__init__.py,sha256=hhT-tt4pQxD7EanesryzxPa9MqIavaU8bj4lrVGXLi0,964
|
44
|
+
fast_clean/services/lock.py,sha256=sWrlEP4rWkKTJgcnR1UrBOnZ8kOvuji4aNWr9VPzjwo,1665
|
45
|
+
fast_clean/services/seed.py,sha256=dytqnztOdvAoja3-bs_ldqf6LnoAUcaGEti2TxTTYOU,3201
|
46
|
+
fast_clean/services/transaction.py,sha256=9XW084PnBgN-g9hBSSDs5NN6QbrsVArBjOLMuhn-W_8,1093
|
47
|
+
fast_clean/services/cryptography/__init__.py,sha256=aXGBi49z9qeaRyTM7ZU9qncN-PfwlSXAJ_WSBuyYMf4,2071
|
48
|
+
fast_clean/services/cryptography/aes.py,sha256=_k0WtnKDaEKdUBegfwmqerE75ER44307CEQ-I2W0abo,4616
|
49
|
+
fast_clean/services/cryptography/enums.py,sha256=cLibSGv6LNVTUI2rm3_DtDwU68GYIAf4kY3GGbtnw1A,494
|
50
|
+
fast_clean/tools/__init__.py,sha256=m8n09uN47JGtAfgWVbXCJOxpzlrUazogqtLo6xPWe3s,181
|
51
|
+
fast_clean/tools/cryptography.py,sha256=NznbY5wtXeX8doyn6Hf76ztakckto5QnsUDK1GK7RWE,2001
|
52
|
+
fast_clean/tools/load_seed.py,sha256=Bql-c-hjFdrf-qsGo5V7DSX9sa9_RCk_P9BLF7G5xts,910
|
53
|
+
fast_clean/utils/__init__.py,sha256=Q3OiJNdWl51Vd_wSP7iuZQIq4_SjM1mYkqIWPaw94WU,709
|
54
|
+
fast_clean/utils/process.py,sha256=6k2E1q7d31Wq6G5BqJqrX5czimvJExeltk7uO7CxiSg,936
|
55
|
+
fast_clean/utils/pydantic.py,sha256=FtBkNsxdlrhrlEiIHu2wZwF-UR4THETV8mw-h_jevYg,871
|
56
|
+
fast_clean/utils/ssl_context.py,sha256=I3tM9bDB6LVMaKCDcrpREzBE4AoTWr3NQDU3_A0Kt3k,904
|
57
|
+
fast_clean/utils/string.py,sha256=8Dy3MeDHn-V9SUknuYZp8M6iakuU_UAmkMC9UreoN8k,630
|
58
|
+
fast_clean/utils/thread.py,sha256=ChEWBLupnSEMq4Wro_aiW0QvCLUKedKc0TQFMu7Zg4g,565
|
59
|
+
fast_clean/utils/time.py,sha256=nvavbtG4zR_gkrGSbsqKAsBdePxO3LuTeoISbFZIgn0,307
|
60
|
+
fast_clean/utils/type_converters.py,sha256=bMEJeoQB9Q6Qok1-ppn4Ii8ZpIkZwJbD2IzCydSStHw,523
|
61
|
+
fast_clean/utils/typer.py,sha256=1O7BsNGn68bBzNbj0-Ycfhv35WpLzwvYTKn510YNXQQ,663
|
62
|
+
fast_clean-0.4.0.dist-info/METADATA,sha256=h8qZAmNHcHtt9YXK4eJyw5uxEOG0d-q3aG3TVNOUncY,1030
|
63
|
+
fast_clean-0.4.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
64
|
+
fast_clean-0.4.0.dist-info/top_level.txt,sha256=QfsGs-QLmPCZWWPFOukD0zhMnokH68FoO2KeObl6ZIA,11
|
65
|
+
fast_clean-0.4.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
fast_clean
|