arpakitlib 1.9.6__tar.gz → 1.9.23__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.
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/PKG-INFO +7 -9
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/README.md +6 -6
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_aiogram_as_tg_command_2_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_aiogram_as_tg_command_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_arpakit_project_template_util.py +0 -2
- arpakitlib-1.9.6/arpakitlib/ar_arpakit_lib_module_util.py → arpakitlib-1.9.23/arpakitlib/ar_arpakitlib_module_util.py +4 -17
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_base64_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_base_http_api_client_util.py +3 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_base_worker_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_blank_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_cache_file_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_class_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_clone_pydantic_model_fields_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_datetime_util.py +0 -2
- arpakitlib-1.9.23/arpakitlib/ar_dict_as_object.py +46 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_dict_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_encrypt_decrypt_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_enumeration_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_exception_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_file_storage_in_dir_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_file_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_func_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_hash_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_http_request_util.py +0 -2
- arpakitlib-1.9.23/arpakitlib/ar_include_aiogram_routers_from_dir_util.py +38 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_ip_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_json_db_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_json_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_jwt_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_list_of_dicts_to_xlsx_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_list_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_log_async_func_if_error_util.py +0 -1
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_logging_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_need_type_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_openai_api_client_util.py +2 -1
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_parse_command_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_postgresql_util.py +20 -11
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_pydantic_schema_from_sqlalchemy_model_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_raise_own_exception_if_exception_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_retry_func_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_run_cmd_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_safe_func_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_settings_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sleep_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_base_dbm_util.py +10 -7
- arpakitlib-1.9.23/arpakitlib/ar_sqlalchemy_etc_util.py +23 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_str_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_type_util.py +0 -2
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_yookassa_api_client_util.py +4 -4
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/pyproject.toml +1 -3
- arpakitlib-1.9.6/arpakitlib/ar_mongodb_util.py +0 -122
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/LICENSE +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/__init__.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_generate_connection_url_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_generate_difficult_password_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_generate_simple_code_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_include_fastapi_routers_from_dir_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_rat_func_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_really_validate_email_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_really_validate_url_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqladmin_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_drop_check_constraints_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_ensure_check_constraints_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_ssh_keys_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_ssh_runner_util.py +0 -0
- {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_uppercase_env_keys_util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arpakitlib
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.23
|
|
4
4
|
Summary: arpakitlib
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -37,7 +37,6 @@ Requires-Dist: markdown (>=3.7,<4.0)
|
|
|
37
37
|
Requires-Dist: openai (>=2.6.1,<3.0.0)
|
|
38
38
|
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
|
|
39
39
|
Requires-Dist: orjson (>=3.10.15,<4.0.0)
|
|
40
|
-
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
|
41
40
|
Requires-Dist: paramiko (>=4.0.0,<5.0.0)
|
|
42
41
|
Requires-Dist: pika (>=1.3.2,<2.0.0)
|
|
43
42
|
Requires-Dist: poetry (>=2.0.1,<3.0.0)
|
|
@@ -47,7 +46,6 @@ Requires-Dist: pulp (>=2.9.0,<3.0.0)
|
|
|
47
46
|
Requires-Dist: pydantic (>=2.10.5,<3.0.0)
|
|
48
47
|
Requires-Dist: pydantic-settings (>=2.7.1,<3.0.0)
|
|
49
48
|
Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
|
|
50
|
-
Requires-Dist: pymongo (>=4.10.1,<5.0.0)
|
|
51
49
|
Requires-Dist: pytelegrambotapi (>=4.29.1,<5.0.0)
|
|
52
50
|
Requires-Dist: pytest (>=8.4.2,<9.0.0)
|
|
53
51
|
Requires-Dist: pytz (>=2024.2,<2025.0)
|
|
@@ -77,21 +75,21 @@ Description-Content-Type: text/markdown
|
|
|
77
75
|
A collection of lightweight and convenient development tools by arpakit, designed to simplify and accelerate your
|
|
78
76
|
workflow
|
|
79
77
|
|
|
80
|
-
## Important
|
|
81
|
-
|
|
82
|
-
The most up-to-date version is on GitHub or GitLab.
|
|
83
|
-
|
|
84
78
|
---
|
|
85
79
|
|
|
86
80
|
### Supported Python version
|
|
87
81
|
|
|
88
|
-
- Python 3.12.4
|
|
82
|
+
- Python 3.12.4+
|
|
89
83
|
|
|
90
84
|
---
|
|
91
85
|
|
|
92
|
-
### Installation
|
|
86
|
+
### Installation methods
|
|
93
87
|
|
|
94
88
|
```
|
|
89
|
+
poetry add arpakitlib
|
|
90
|
+
# or
|
|
91
|
+
pip add arpakitlib
|
|
92
|
+
# or
|
|
95
93
|
poetry add git+https://github.com/ARPAKIT-Company/arpakitlib.git@master
|
|
96
94
|
```
|
|
97
95
|
|
|
@@ -5,21 +5,21 @@
|
|
|
5
5
|
A collection of lightweight and convenient development tools by arpakit, designed to simplify and accelerate your
|
|
6
6
|
workflow
|
|
7
7
|
|
|
8
|
-
## Important
|
|
9
|
-
|
|
10
|
-
The most up-to-date version is on GitHub or GitLab.
|
|
11
|
-
|
|
12
8
|
---
|
|
13
9
|
|
|
14
10
|
### Supported Python version
|
|
15
11
|
|
|
16
|
-
- Python 3.12.4
|
|
12
|
+
- Python 3.12.4+
|
|
17
13
|
|
|
18
14
|
---
|
|
19
15
|
|
|
20
|
-
### Installation
|
|
16
|
+
### Installation methods
|
|
21
17
|
|
|
22
18
|
```
|
|
19
|
+
poetry add arpakitlib
|
|
20
|
+
# or
|
|
21
|
+
pip add arpakitlib
|
|
22
|
+
# or
|
|
23
23
|
poetry add git+https://github.com/ARPAKIT-Company/arpakitlib.git@master
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -15,8 +15,6 @@ from arpakitlib.ar_need_type_util import parse_need_type, NeedTypes
|
|
|
15
15
|
from arpakitlib.ar_parse_command_util import BadCommandFormat, parse_command
|
|
16
16
|
from arpakitlib.ar_type_util import raise_for_types
|
|
17
17
|
|
|
18
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
19
|
-
|
|
20
18
|
_logger = logging.getLogger(__name__)
|
|
21
19
|
|
|
22
20
|
_logger.warning(f"Module '{Path(__file__).name}' is deprecated; use 'ar_aiogram_as_tg_command_2_util' instead.")
|
|
@@ -4,14 +4,11 @@ import json
|
|
|
4
4
|
import os
|
|
5
5
|
import pathlib
|
|
6
6
|
from importlib.util import spec_from_file_location, module_from_spec
|
|
7
|
-
from typing import NamedTuple, Any, Iterator
|
|
8
|
-
|
|
9
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
7
|
+
from typing import NamedTuple, Any, Iterator
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
class ArpakitLibModule(NamedTuple):
|
|
13
11
|
module_name: str
|
|
14
|
-
module_version: Optional[str]
|
|
15
12
|
module_content: str
|
|
16
13
|
module_hash: str
|
|
17
14
|
module_has_error: bool
|
|
@@ -22,7 +19,6 @@ class ArpakitLibModule(NamedTuple):
|
|
|
22
19
|
def simple_dict(self) -> dict[str, Any]:
|
|
23
20
|
return {
|
|
24
21
|
"module_name": self.module_name,
|
|
25
|
-
"module_version": self.module_version,
|
|
26
22
|
"module_content": self.module_content,
|
|
27
23
|
"module_hash": self.module_hash,
|
|
28
24
|
"module_has_error": self.module_has_error,
|
|
@@ -61,13 +57,9 @@ class ArpakitLibModules(NamedTuple):
|
|
|
61
57
|
def module_name_to_module_simple_dict(self) -> dict[str, dict]:
|
|
62
58
|
return {module.module_name: module.simple_dict() for module in self.arpakit_lib_modules}
|
|
63
59
|
|
|
64
|
-
def
|
|
65
|
-
return {module.module_name: module.module_version for module in self.arpakit_lib_modules}
|
|
66
|
-
|
|
67
|
-
def module_name_to_module_version_and_module_has_errors(self) -> dict[str, dict[str, Any]]:
|
|
60
|
+
def module_name_to_has_errors(self) -> dict[str, dict[str, Any]]:
|
|
68
61
|
return {
|
|
69
62
|
module.module_name: {
|
|
70
|
-
"module_version": module.module_version,
|
|
71
63
|
"module_has_errors": module.module_has_error,
|
|
72
64
|
} for module in self.arpakit_lib_modules
|
|
73
65
|
}
|
|
@@ -104,7 +96,7 @@ class ArpakitLibModules(NamedTuple):
|
|
|
104
96
|
return {module.module_name: module.module_content for module in self.arpakit_lib_modules}
|
|
105
97
|
|
|
106
98
|
|
|
107
|
-
def
|
|
99
|
+
def get_arpakitlib_modules() -> ArpakitLibModules:
|
|
108
100
|
base_dirpath: str = str(pathlib.Path(__file__).parent)
|
|
109
101
|
|
|
110
102
|
filenames: list[str] = os.listdir(base_dirpath)
|
|
@@ -116,19 +108,15 @@ def get_arpakit_lib_modules() -> ArpakitLibModules:
|
|
|
116
108
|
if not filename.endswith(".py") or filename == "__init__.py":
|
|
117
109
|
continue
|
|
118
110
|
module_name = filename.replace(".py", "")
|
|
119
|
-
module_version: Optional[str] = None
|
|
120
111
|
try:
|
|
121
112
|
spec = spec_from_file_location(module_name, os.path.join(base_dirpath, filename))
|
|
122
113
|
module = module_from_spec(spec)
|
|
123
114
|
spec.loader.exec_module(module)
|
|
124
|
-
module_version = getattr(module, "_ARPAKIT_LIB_MODULE_VERSION", None)
|
|
125
115
|
module_has_error = False
|
|
126
116
|
module_exception = None
|
|
127
117
|
except Exception as error:
|
|
128
118
|
module_has_error = True
|
|
129
119
|
module_exception = error
|
|
130
|
-
if module_version is not None and not isinstance(module_version, str):
|
|
131
|
-
continue
|
|
132
120
|
if module_name in [
|
|
133
121
|
arpakit_lib_module.module_name for arpakit_lib_module in arpakit_lib_modules.arpakit_lib_modules
|
|
134
122
|
]:
|
|
@@ -137,7 +125,6 @@ def get_arpakit_lib_modules() -> ArpakitLibModules:
|
|
|
137
125
|
module_hash = hashlib.sha256(module_content.encode('utf-8')).hexdigest()
|
|
138
126
|
arpakit_lib_modules.arpakit_lib_modules.append(ArpakitLibModule(
|
|
139
127
|
module_name=module_name,
|
|
140
|
-
module_version=module_version,
|
|
141
128
|
module_content=module_content,
|
|
142
129
|
module_hash=module_hash,
|
|
143
130
|
module_has_error=module_has_error,
|
|
@@ -150,7 +137,7 @@ def get_arpakit_lib_modules() -> ArpakitLibModules:
|
|
|
150
137
|
|
|
151
138
|
|
|
152
139
|
def __example():
|
|
153
|
-
|
|
140
|
+
print(get_arpakitlib_modules())
|
|
154
141
|
|
|
155
142
|
|
|
156
143
|
if __name__ == '__main__':
|
|
@@ -14,8 +14,6 @@ from arpakitlib.ar_enumeration_util import Enumeration
|
|
|
14
14
|
from arpakitlib.ar_func_util import is_async_func, is_sync_func, is_coroutine
|
|
15
15
|
from arpakitlib.ar_sleep_util import sync_safe_sleep, async_safe_sleep
|
|
16
16
|
|
|
17
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
18
|
-
|
|
19
17
|
|
|
20
18
|
class BaseWorker(ABC):
|
|
21
19
|
def __init__(
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from arpakitlib.ar_json_util import transfer_data_to_json_str
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DictAsObject:
|
|
5
|
+
def __init__(self, data: dict | list):
|
|
6
|
+
self._real_data = data
|
|
7
|
+
|
|
8
|
+
def __getattr__(self, item):
|
|
9
|
+
if isinstance(self._real_data, dict):
|
|
10
|
+
try:
|
|
11
|
+
return self.wrap(self._real_data[item])
|
|
12
|
+
except KeyError:
|
|
13
|
+
raise AttributeError(item)
|
|
14
|
+
|
|
15
|
+
raise AttributeError(item)
|
|
16
|
+
|
|
17
|
+
def __getitem__(self, key):
|
|
18
|
+
if isinstance(self._real_data, (list, dict)):
|
|
19
|
+
return self.wrap(self._real_data[key])
|
|
20
|
+
raise TypeError(f"{type(self._real_data)} is not subscriptable")
|
|
21
|
+
|
|
22
|
+
def __len__(self):
|
|
23
|
+
return len(self._real_data)
|
|
24
|
+
|
|
25
|
+
def __repr__(self):
|
|
26
|
+
return transfer_data_to_json_str(self._real_data, beautify=True)
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def wrap(value):
|
|
30
|
+
if isinstance(value, (dict, list)):
|
|
31
|
+
return DictAsObject(value)
|
|
32
|
+
return value
|
|
33
|
+
|
|
34
|
+
def get_raw_from_dict(self, *, key: str, allow_non_exist: bool = True):
|
|
35
|
+
"""
|
|
36
|
+
Возвращает значение напрямую из _real_data, без wrap
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
if not isinstance(self._real_data, dict):
|
|
40
|
+
raise TypeError("not isinstance(self._real_data, dict)")
|
|
41
|
+
|
|
42
|
+
if key not in self._real_data:
|
|
43
|
+
if allow_non_exist is True:
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
return self._real_data[key]
|
|
@@ -13,8 +13,6 @@ from arpakitlib.ar_json_util import transfer_data_to_json_str
|
|
|
13
13
|
from arpakitlib.ar_sleep_util import sync_safe_sleep, async_safe_sleep
|
|
14
14
|
from arpakitlib.ar_type_util import raise_for_type
|
|
15
15
|
|
|
16
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
17
|
-
|
|
18
16
|
_logger = logging.getLogger(__name__)
|
|
19
17
|
|
|
20
18
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from aiogram import Router
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def include_aiogram_routers_from_dir(
|
|
8
|
+
*,
|
|
9
|
+
router: Router,
|
|
10
|
+
base_dir: str = ".",
|
|
11
|
+
exclude_filenames: list[str] | None = None,
|
|
12
|
+
):
|
|
13
|
+
if exclude_filenames is None:
|
|
14
|
+
exclude_filenames = ["__init__.py"]
|
|
15
|
+
|
|
16
|
+
for root, _, files in os.walk(base_dir):
|
|
17
|
+
files.sort()
|
|
18
|
+
|
|
19
|
+
for filename in files:
|
|
20
|
+
if not filename.endswith(".py") or filename in exclude_filenames:
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
file_path = os.path.join(root, filename)
|
|
24
|
+
module_name = (
|
|
25
|
+
os.path.relpath(file_path, base_dir)
|
|
26
|
+
.replace(os.sep, ".")
|
|
27
|
+
.removesuffix(".py")
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
|
31
|
+
module = importlib.util.module_from_spec(spec)
|
|
32
|
+
spec.loader.exec_module(module)
|
|
33
|
+
|
|
34
|
+
tg_bot_router = getattr(module, "tg_bot_router", None)
|
|
35
|
+
if isinstance(tg_bot_router, Router):
|
|
36
|
+
router.include_router(
|
|
37
|
+
router=tg_bot_router,
|
|
38
|
+
)
|
|
@@ -4,10 +4,11 @@ import asyncio
|
|
|
4
4
|
import logging
|
|
5
5
|
|
|
6
6
|
import httpx
|
|
7
|
-
from arpakitlib.ar_base64_util import convert_file_to_base64_string
|
|
8
7
|
from openai import OpenAI, AsyncOpenAI
|
|
9
8
|
from openai.types.chat import ChatCompletion
|
|
10
9
|
|
|
10
|
+
from arpakitlib.ar_base64_util import convert_file_to_base64_string
|
|
11
|
+
|
|
11
12
|
"""
|
|
12
13
|
https://platform.openai.com/docs/
|
|
13
14
|
"""
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# arpakit
|
|
2
2
|
|
|
3
|
+
from shlex import quote
|
|
4
|
+
|
|
3
5
|
from arpakitlib.ar_run_cmd_util import run_cmd
|
|
4
6
|
from arpakitlib.ar_type_util import raise_for_type
|
|
5
7
|
|
|
6
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
7
|
-
|
|
8
8
|
|
|
9
9
|
def make_postgresql_db_dump(
|
|
10
10
|
*,
|
|
@@ -13,21 +13,30 @@ def make_postgresql_db_dump(
|
|
|
13
13
|
db_name: str,
|
|
14
14
|
port: int = 5432,
|
|
15
15
|
out_filepath: str = "db_dump.sql",
|
|
16
|
-
password: str | None = None
|
|
16
|
+
password: str | None = None,
|
|
17
17
|
) -> str:
|
|
18
18
|
raise_for_type(user, str)
|
|
19
19
|
raise_for_type(host, str)
|
|
20
20
|
raise_for_type(db_name, str)
|
|
21
21
|
raise_for_type(port, int)
|
|
22
|
+
raise_for_type(out_filepath, str)
|
|
23
|
+
|
|
24
|
+
env_prefix = ""
|
|
22
25
|
if password:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
|
|
26
|
+
env_prefix = f"PGPASSWORD={quote(password)} "
|
|
27
|
+
|
|
28
|
+
command = (
|
|
29
|
+
f"{env_prefix}"
|
|
30
|
+
f"pg_dump "
|
|
31
|
+
f"-U {quote(user)} "
|
|
32
|
+
f"-h {quote(host)} "
|
|
33
|
+
f"-p {port} "
|
|
34
|
+
f"-f {quote(out_filepath)} "
|
|
35
|
+
f"{quote(db_name)}"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
res = run_cmd(command)
|
|
39
|
+
res.raise_for_bad_return_code()
|
|
31
40
|
|
|
32
41
|
return out_filepath
|
|
33
42
|
|
|
@@ -6,8 +6,6 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
|
6
6
|
|
|
7
7
|
from arpakitlib.ar_datetime_util import now_utc_dt
|
|
8
8
|
|
|
9
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
class SafeFuncResult(BaseModel):
|
|
13
11
|
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True, from_attributes=True)
|
|
@@ -5,8 +5,6 @@ from pydantic import ConfigDict, model_validator
|
|
|
5
5
|
from pydantic_core import PydanticUndefined
|
|
6
6
|
from pydantic_settings import BaseSettings
|
|
7
7
|
|
|
8
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
9
|
-
|
|
10
8
|
|
|
11
9
|
def generate_env_example(settings_class: Union[BaseSettings, type[BaseSettings]]) -> str:
|
|
12
10
|
res = ""
|
|
@@ -13,8 +13,6 @@ from sqlalchemy.orm.session import Session
|
|
|
13
13
|
|
|
14
14
|
from arpakitlib.ar_datetime_util import now_utc_dt
|
|
15
15
|
|
|
16
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
17
|
-
|
|
18
16
|
|
|
19
17
|
class BaseDBM(DeclarativeBase):
|
|
20
18
|
__abstract__ = True
|
|
@@ -26,7 +24,8 @@ class BaseDBM(DeclarativeBase):
|
|
|
26
24
|
*,
|
|
27
25
|
include_pk: bool = True,
|
|
28
26
|
exclude_names: list[str] | None = None,
|
|
29
|
-
exclude_if_have_foreign_keys: bool = False
|
|
27
|
+
exclude_if_have_foreign_keys: bool = False,
|
|
28
|
+
filter_prefixes: list[str] | None = None
|
|
30
29
|
) -> list[str]:
|
|
31
30
|
if exclude_names is None:
|
|
32
31
|
exclude_names = []
|
|
@@ -38,6 +37,10 @@ class BaseDBM(DeclarativeBase):
|
|
|
38
37
|
continue
|
|
39
38
|
if exclude_if_have_foreign_keys and c.foreign_keys:
|
|
40
39
|
continue
|
|
40
|
+
if filter_prefixes is not None and not any(
|
|
41
|
+
c.key.startswith(prefix) for prefix in filter_prefixes
|
|
42
|
+
):
|
|
43
|
+
continue
|
|
41
44
|
res.append(c.key)
|
|
42
45
|
return res
|
|
43
46
|
|
|
@@ -257,8 +260,8 @@ class SQLAlchemyDb:
|
|
|
257
260
|
self.engine = create_engine(
|
|
258
261
|
url=sync_db_url,
|
|
259
262
|
echo=db_echo,
|
|
260
|
-
pool_size=
|
|
261
|
-
max_overflow=
|
|
263
|
+
pool_size=20,
|
|
264
|
+
max_overflow=30,
|
|
262
265
|
poolclass=QueuePool,
|
|
263
266
|
pool_timeout=timedelta(seconds=30).total_seconds(),
|
|
264
267
|
)
|
|
@@ -270,8 +273,8 @@ class SQLAlchemyDb:
|
|
|
270
273
|
self.async_engine = create_async_engine(
|
|
271
274
|
url=async_db_url,
|
|
272
275
|
echo=db_echo,
|
|
273
|
-
pool_size=
|
|
274
|
-
max_overflow=
|
|
276
|
+
pool_size=20,
|
|
277
|
+
max_overflow=30,
|
|
275
278
|
poolclass=AsyncAdaptedQueuePool,
|
|
276
279
|
pool_timeout=timedelta(seconds=30).total_seconds()
|
|
277
280
|
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _str_no_self(v: str) -> str:
|
|
5
|
+
return v.replace("self.", "").strip()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def generate_sqlalchemy_model_repr(*, title: str, parts: list[Any]):
|
|
9
|
+
res = []
|
|
10
|
+
for part in parts:
|
|
11
|
+
if part is None:
|
|
12
|
+
continue
|
|
13
|
+
if isinstance(part, int):
|
|
14
|
+
part = str(part)
|
|
15
|
+
elif isinstance(part, bool):
|
|
16
|
+
part = str(part)
|
|
17
|
+
elif isinstance(part, str):
|
|
18
|
+
part = _str_no_self(part)
|
|
19
|
+
part = part.strip()
|
|
20
|
+
if not part:
|
|
21
|
+
continue
|
|
22
|
+
res.append(part)
|
|
23
|
+
return f"{title} ({', '.join(res)})"
|
|
@@ -47,9 +47,9 @@ class EasyYookassaAPIClient(BaseHTTPAPIClient):
|
|
|
47
47
|
method=method,
|
|
48
48
|
url=url,
|
|
49
49
|
headers=combine_dicts(self.headers, (headers if headers is not None else {})),
|
|
50
|
-
max_tries_=
|
|
50
|
+
max_tries_=1,
|
|
51
51
|
raise_for_status_=True,
|
|
52
|
-
timeout_=timedelta(seconds=
|
|
52
|
+
timeout_=timedelta(seconds=5),
|
|
53
53
|
not_raise_for_statuses_=not_raise_for_statuses_,
|
|
54
54
|
auth=(self.shop_id, self.secret_key),
|
|
55
55
|
enable_logging_=False,
|
|
@@ -69,10 +69,10 @@ class EasyYookassaAPIClient(BaseHTTPAPIClient):
|
|
|
69
69
|
method=method,
|
|
70
70
|
url=url,
|
|
71
71
|
headers=combine_dicts(self.headers, (headers if headers is not None else {})),
|
|
72
|
-
max_tries_=
|
|
72
|
+
max_tries_=1,
|
|
73
73
|
raise_for_status_=True,
|
|
74
74
|
not_raise_for_statuses_=not_raise_for_statuses_,
|
|
75
|
-
timeout_=timedelta(seconds=
|
|
75
|
+
timeout_=timedelta(seconds=5),
|
|
76
76
|
auth=aiohttp.BasicAuth(login=str(self.shop_id), password=self.secret_key),
|
|
77
77
|
enable_logging_=False,
|
|
78
78
|
**kwargs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "arpakitlib"
|
|
3
|
-
version = "1.9.
|
|
3
|
+
version = "1.9.23"
|
|
4
4
|
description = "arpakitlib"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "arpakit_company", email = "support@arpakit.com" }
|
|
@@ -34,13 +34,11 @@ dependencies = [
|
|
|
34
34
|
"cachetools (>=5.5.1,<6.0.0)",
|
|
35
35
|
"bs4 (>=0.0.2,<0.0.3)",
|
|
36
36
|
"celery (>=5.4.0,<6.0.0)",
|
|
37
|
-
"pandas (>=2.2.3,<3.0.0)",
|
|
38
37
|
"twine (>=6.1.0,<7.0.0)",
|
|
39
38
|
"itsdangerous (>=2.2.0,<3.0.0)",
|
|
40
39
|
"email-validator (>=2.2.0,<3.0.0)",
|
|
41
40
|
"openpyxl (>=3.1.5,<4.0.0)",
|
|
42
41
|
"alembic (>=1.14.1,<2.0.0)",
|
|
43
|
-
"pymongo (>=4.10.1,<5.0.0)",
|
|
44
42
|
"pydantic (>=2.10.5,<3.0.0)",
|
|
45
43
|
"pika (>=1.3.2,<2.0.0)",
|
|
46
44
|
"aio-pika (>=9.5.4,<10.0.0)",
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# arpakit
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import logging
|
|
5
|
-
from abc import abstractmethod
|
|
6
|
-
from random import randint
|
|
7
|
-
|
|
8
|
-
from pymongo import MongoClient
|
|
9
|
-
from pymongo.collection import Collection
|
|
10
|
-
from pymongo.database import Database
|
|
11
|
-
|
|
12
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class EasyMongoDb:
|
|
16
|
-
def __init__(
|
|
17
|
-
self,
|
|
18
|
-
*,
|
|
19
|
-
db_name: str,
|
|
20
|
-
username: str | None = None,
|
|
21
|
-
password: str | None = None,
|
|
22
|
-
hostname: str = "127.0.0.1",
|
|
23
|
-
port: int = 27017,
|
|
24
|
-
auth_source: str | None = None,
|
|
25
|
-
):
|
|
26
|
-
self._logger = logging.getLogger(self.__class__.__name__)
|
|
27
|
-
self.hostname = hostname
|
|
28
|
-
self.username = username
|
|
29
|
-
self.password = password
|
|
30
|
-
self.auth_source = auth_source
|
|
31
|
-
self.port = port
|
|
32
|
-
self.db_name = db_name
|
|
33
|
-
self.used_collections: list[Collection] = []
|
|
34
|
-
|
|
35
|
-
def init(self):
|
|
36
|
-
self.ensure_indexes()
|
|
37
|
-
|
|
38
|
-
def reinit(self):
|
|
39
|
-
self.drop_all_collections()
|
|
40
|
-
self.init()
|
|
41
|
-
|
|
42
|
-
def get_pymongo_client(self) -> MongoClient:
|
|
43
|
-
kwargs = {
|
|
44
|
-
"host": self.hostname,
|
|
45
|
-
"port": self.port,
|
|
46
|
-
"tz_aware": True
|
|
47
|
-
}
|
|
48
|
-
if self.username is not None:
|
|
49
|
-
kwargs["username"] = self.username
|
|
50
|
-
if self.password is not None:
|
|
51
|
-
kwargs["password"] = self.password
|
|
52
|
-
if self.auth_source is not None:
|
|
53
|
-
kwargs["authSource"] = self.auth_source
|
|
54
|
-
kwargs["timeoutMS"] = 5000
|
|
55
|
-
kwargs["connectTimeoutMS"] = 5000
|
|
56
|
-
kwargs["socketTimeoutMS"] = 5000
|
|
57
|
-
kwargs["serverSelectionTimeoutMS"] = 5000
|
|
58
|
-
return MongoClient(**kwargs)
|
|
59
|
-
|
|
60
|
-
def check_conn(self):
|
|
61
|
-
self.get_pymongo_client().server_info()
|
|
62
|
-
|
|
63
|
-
def is_db_conn_good(self) -> bool:
|
|
64
|
-
try:
|
|
65
|
-
self.get_pymongo_client().server_info()
|
|
66
|
-
except Exception as e:
|
|
67
|
-
self._logger.error(e)
|
|
68
|
-
return False
|
|
69
|
-
return True
|
|
70
|
-
|
|
71
|
-
def get_pymongo_db(self) -> Database:
|
|
72
|
-
return self.get_pymongo_client().get_database(self.db_name)
|
|
73
|
-
|
|
74
|
-
def drop_all_collections(self):
|
|
75
|
-
for collection in self.get_pymongo_db().list_collections():
|
|
76
|
-
self.get_pymongo_db().get_collection(collection["name"]).drop()
|
|
77
|
-
|
|
78
|
-
def drop_used_collections(self):
|
|
79
|
-
for collection in self.used_collections:
|
|
80
|
-
collection.drop()
|
|
81
|
-
|
|
82
|
-
def generate_collection_int_id(self, collection: Collection) -> int:
|
|
83
|
-
existing_ids = set(
|
|
84
|
-
doc["id"] for doc in collection.find({}, {"id": True}) if "id" in doc.keys()
|
|
85
|
-
)
|
|
86
|
-
if existing_ids:
|
|
87
|
-
res = max(existing_ids) + 1
|
|
88
|
-
else:
|
|
89
|
-
res = 1
|
|
90
|
-
while res in existing_ids:
|
|
91
|
-
res += 1
|
|
92
|
-
return res
|
|
93
|
-
|
|
94
|
-
def generate_collection_rand_int_id(self, collection: Collection, max_rand_int: int = 30) -> int:
|
|
95
|
-
existing_ids = set(
|
|
96
|
-
doc["id"] for doc in collection.find({}, {"id": True}) if "id" in doc.keys()
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
id_ = self.generate_collection_int_id(collection=collection)
|
|
100
|
-
res = id_ + randint(1, max_rand_int)
|
|
101
|
-
while res in existing_ids:
|
|
102
|
-
id_ += 1
|
|
103
|
-
res = id_ + randint(1, max_rand_int)
|
|
104
|
-
|
|
105
|
-
return res
|
|
106
|
-
|
|
107
|
-
@abstractmethod
|
|
108
|
-
def ensure_indexes(self):
|
|
109
|
-
raise NotImplemented()
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def __example():
|
|
113
|
-
pass
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
async def __async_example():
|
|
117
|
-
pass
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if __name__ == '__main__':
|
|
121
|
-
__example()
|
|
122
|
-
asyncio.run(__async_example())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_include_fastapi_routers_from_dir_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_drop_check_constraints_util.py
RENAMED
|
File without changes
|
{arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_ensure_check_constraints_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|