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.
Files changed (66) hide show
  1. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/PKG-INFO +7 -9
  2. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/README.md +6 -6
  3. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_aiogram_as_tg_command_2_util.py +0 -2
  4. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_aiogram_as_tg_command_util.py +0 -2
  5. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_arpakit_project_template_util.py +0 -2
  6. arpakitlib-1.9.6/arpakitlib/ar_arpakit_lib_module_util.py → arpakitlib-1.9.23/arpakitlib/ar_arpakitlib_module_util.py +4 -17
  7. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_base64_util.py +0 -2
  8. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_base_http_api_client_util.py +3 -0
  9. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_base_worker_util.py +0 -2
  10. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_blank_util.py +0 -2
  11. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_cache_file_util.py +0 -2
  12. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_class_util.py +0 -2
  13. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_clone_pydantic_model_fields_util.py +0 -2
  14. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_datetime_util.py +0 -2
  15. arpakitlib-1.9.23/arpakitlib/ar_dict_as_object.py +46 -0
  16. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_dict_util.py +0 -2
  17. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_encrypt_decrypt_util.py +0 -2
  18. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_enumeration_util.py +0 -2
  19. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_exception_util.py +0 -2
  20. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_file_storage_in_dir_util.py +0 -2
  21. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_file_util.py +0 -2
  22. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_func_util.py +0 -2
  23. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_hash_util.py +0 -2
  24. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_http_request_util.py +0 -2
  25. arpakitlib-1.9.23/arpakitlib/ar_include_aiogram_routers_from_dir_util.py +38 -0
  26. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_ip_util.py +0 -2
  27. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_json_db_util.py +0 -2
  28. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_json_util.py +0 -2
  29. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_jwt_util.py +0 -2
  30. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_list_of_dicts_to_xlsx_util.py +0 -2
  31. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_list_util.py +0 -2
  32. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_log_async_func_if_error_util.py +0 -1
  33. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_logging_util.py +0 -2
  34. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_need_type_util.py +0 -2
  35. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_openai_api_client_util.py +2 -1
  36. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_parse_command_util.py +0 -2
  37. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_postgresql_util.py +20 -11
  38. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_pydantic_schema_from_sqlalchemy_model_util.py +0 -2
  39. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_raise_own_exception_if_exception_util.py +0 -2
  40. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_retry_func_util.py +0 -2
  41. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_run_cmd_util.py +0 -2
  42. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_safe_func_util.py +0 -2
  43. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_settings_util.py +0 -2
  44. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sleep_util.py +0 -2
  45. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_base_dbm_util.py +10 -7
  46. arpakitlib-1.9.23/arpakitlib/ar_sqlalchemy_etc_util.py +23 -0
  47. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_str_util.py +0 -2
  48. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_type_util.py +0 -2
  49. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_yookassa_api_client_util.py +4 -4
  50. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/pyproject.toml +1 -3
  51. arpakitlib-1.9.6/arpakitlib/ar_mongodb_util.py +0 -122
  52. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/LICENSE +0 -0
  53. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/__init__.py +0 -0
  54. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_generate_connection_url_util.py +0 -0
  55. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_generate_difficult_password_util.py +0 -0
  56. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_generate_simple_code_util.py +0 -0
  57. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_include_fastapi_routers_from_dir_util.py +0 -0
  58. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_rat_func_util.py +0 -0
  59. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_really_validate_email_util.py +0 -0
  60. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_really_validate_url_util.py +0 -0
  61. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqladmin_util.py +0 -0
  62. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_drop_check_constraints_util.py +0 -0
  63. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_sqlalchemy_ensure_check_constraints_util.py +0 -0
  64. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_ssh_keys_util.py +0 -0
  65. {arpakitlib-1.9.6 → arpakitlib-1.9.23}/arpakitlib/ar_ssh_runner_util.py +0 -0
  66. {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.6
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 with Poetry
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 with Poetry
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
 
@@ -13,8 +13,6 @@ from pydantic_core import PydanticUndefined
13
13
 
14
14
  from arpakitlib.ar_parse_command_util import parse_command
15
15
 
16
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
17
-
18
16
  _logger = logging.getLogger(__name__)
19
17
 
20
18
 
@@ -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.")
@@ -6,8 +6,6 @@ import os
6
6
  from arpakitlib.ar_str_util import raise_if_string_blank
7
7
  from arpakitlib.ar_type_util import raise_for_type
8
8
 
9
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
10
-
11
9
  _logger = logging.getLogger(__name__)
12
10
 
13
11
 
@@ -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, Optional
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 module_name_to_module_version(self) -> dict[str, str]:
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 get_arpakit_lib_modules() -> ArpakitLibModules:
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
- pass
140
+ print(get_arpakitlib_modules())
154
141
 
155
142
 
156
143
  if __name__ == '__main__':
@@ -3,8 +3,6 @@
3
3
  import base64
4
4
  from typing import Optional
5
5
 
6
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
7
-
8
6
 
9
7
  def convert_base64_string_to_bytes(base64_string: str, raise_for_error: bool = False) -> Optional[bytes]:
10
8
  try:
@@ -45,3 +45,6 @@ class BaseHTTPAPIClient:
45
45
 
46
46
  def healthcheck(self) -> bool:
47
47
  raise NotImplemented()
48
+
49
+ async def async_healthcheck(self) -> bool:
50
+ raise NotImplemented()
@@ -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__(
@@ -1,8 +1,6 @@
1
1
  # arpakit
2
2
  from arpakitlib.ar_enumeration_util import Enumeration
3
3
 
4
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
5
-
6
4
 
7
5
  class BaseBlank:
8
6
  class Languages(Enumeration):
@@ -10,8 +10,6 @@ from pydantic import BaseModel
10
10
  from arpakitlib.ar_json_db_util import JSONDbFile
11
11
  from arpakitlib.ar_type_util import raise_for_type
12
12
 
13
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
14
-
15
13
 
16
14
  class CacheBlock(BaseModel):
17
15
  key: str
@@ -1,7 +1,5 @@
1
1
  # arpakit
2
2
 
3
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
-
5
3
 
6
4
  class CollectingSubclassesMeta(type):
7
5
  """
@@ -4,8 +4,6 @@ from typing import Any, Type, Iterable
4
4
  from pydantic import BaseModel, create_model
5
5
  from pydantic_core import PydanticUndefined
6
6
 
7
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
8
-
9
7
 
10
8
  def clone_pydantic_model_fields(
11
9
  *,
@@ -7,8 +7,6 @@ import pytz
7
7
 
8
8
  from arpakitlib.ar_type_util import raise_for_type
9
9
 
10
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
11
-
12
10
 
13
11
  def convert_dt_tz(dt: datetime, tz_info):
14
12
  return dt.astimezone(tz_info)
@@ -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]
@@ -2,8 +2,6 @@
2
2
 
3
3
  from typing import Any
4
4
 
5
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
-
7
5
 
8
6
  def combine_dicts(*dicts: dict) -> dict[Any, Any]:
9
7
  res = {}
@@ -2,8 +2,6 @@
2
2
 
3
3
  from cryptography.fernet import Fernet
4
4
 
5
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
-
7
5
 
8
6
  def generate_secret_key() -> str:
9
7
  return Fernet.generate_key().decode()
@@ -2,8 +2,6 @@
2
2
 
3
3
  from typing import Union, Iterator, Iterable, Any
4
4
 
5
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
-
7
5
  ValueType = Union[int, str]
8
6
  ValuesForParseType = Union[ValueType, Iterable[ValueType]]
9
7
 
@@ -1,7 +1,5 @@
1
1
  import traceback
2
2
 
3
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
-
5
3
 
6
4
  def exception_to_traceback_str(exception: BaseException) -> str:
7
5
  try:
@@ -9,8 +9,6 @@ from typing import Optional, Union, Iterator
9
9
  from arpakitlib.ar_datetime_util import now_utc_dt
10
10
  from arpakitlib.ar_str_util import none_if_blank
11
11
 
12
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
13
-
14
12
 
15
13
  class FileStorageInDir:
16
14
 
@@ -1,7 +1,5 @@
1
1
  import os
2
2
 
3
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
-
5
3
 
6
4
  def raise_if_path_not_exists(path: str):
7
5
  if not os.path.exists(path):
@@ -2,8 +2,6 @@ import asyncio
2
2
  import inspect
3
3
  from typing import Callable
4
4
 
5
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
-
7
5
 
8
6
  def is_async_func(func: Callable) -> bool:
9
7
  if inspect.ismethod(func) or inspect.isfunction(func):
@@ -2,8 +2,6 @@
2
2
 
3
3
  import hashlib
4
4
 
5
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
-
7
5
 
8
6
  def hash_string(string: str) -> str:
9
7
  return hashlib.sha256(string.encode()).hexdigest()
@@ -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
+ )
@@ -2,8 +2,6 @@
2
2
 
3
3
  import ipaddress
4
4
 
5
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
-
7
5
 
8
6
  def is_ipv4_address(value: str) -> bool:
9
7
  try:
@@ -8,8 +8,6 @@ from typing import Any, Optional, Self
8
8
 
9
9
  from arpakitlib.ar_type_util import raise_for_type
10
10
 
11
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
12
-
13
11
 
14
12
  class JSONDbFile:
15
13
 
@@ -5,8 +5,6 @@ from typing import Any, Iterable
5
5
 
6
6
  import orjson
7
7
 
8
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
9
-
10
8
 
11
9
  def transfer_json_str_to_data(
12
10
  json_str: str, fast: bool = False
@@ -7,8 +7,6 @@ from jwt import PyJWTError
7
7
 
8
8
  from arpakitlib.ar_type_util import raise_for_type
9
9
 
10
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
11
-
12
10
 
13
11
  def encode_jwt_token(
14
12
  *,
@@ -4,8 +4,6 @@ from typing import Any
4
4
 
5
5
  import pandas
6
6
 
7
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
8
-
9
7
 
10
8
  def list_of_dicts_to_xlsx(
11
9
  list_of_dicts: list[dict[str, Any]],
@@ -2,8 +2,6 @@
2
2
 
3
3
  from typing import Any
4
4
 
5
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
-
7
5
 
8
6
  def iter_group_list(list_: list[Any], n: int):
9
7
  part = []
@@ -1,6 +1,5 @@
1
1
  # arpakit
2
2
 
3
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
3
 
5
4
  import logging
6
5
 
@@ -3,8 +3,6 @@
3
3
  import logging
4
4
  import os
5
5
 
6
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
7
-
8
6
 
9
7
  def init_log_file(*, log_filepath: str | None):
10
8
  if not log_filepath:
@@ -5,8 +5,6 @@ from typing import Any
5
5
 
6
6
  from arpakitlib.ar_enumeration_util import Enumeration
7
7
 
8
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
9
-
10
8
 
11
9
  class NeedTypes(Enumeration):
12
10
  str_ = "str"
@@ -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
  """
@@ -4,8 +4,6 @@ import shlex
4
4
 
5
5
  from pydantic import BaseModel
6
6
 
7
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
8
-
9
7
 
10
8
  class BadCommandFormat(Exception):
11
9
  pass
@@ -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
- run_cmd_res = run_cmd(
24
- command=f"echo {password} | pg_dump -U {user} -h {host} {db_name} -p {port} > {out_filepath}"
25
- )
26
- else:
27
- run_cmd_res = run_cmd(
28
- command=f"pg_dump -U {user} -h {host} {db_name} -p {port} > {out_filepath}"
29
- )
30
- run_cmd_res.raise_for_bad_return_code()
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
 
@@ -5,8 +5,6 @@ from pydantic import BaseModel, ConfigDict
5
5
  from sqlalchemy import inspect
6
6
  from sqlalchemy.orm import ColumnProperty, Mapped
7
7
 
8
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
9
-
10
8
 
11
9
  def _define_sqlalchemy_column_mapped_type(type_: Any) -> Any:
12
10
  """
@@ -5,8 +5,6 @@ import logging
5
5
  from functools import wraps
6
6
  from typing import Any, Callable, Awaitable, Tuple, TypeVar, ParamSpec, cast
7
7
 
8
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
9
-
10
8
  PARAMS_SPEC = ParamSpec("PARAMS_SPEC")
11
9
  RESULT_SPEC = TypeVar("RESULT_SPEC")
12
10
 
@@ -7,8 +7,6 @@ from typing import Any
7
7
 
8
8
  from arpakitlib.ar_sleep_util import sync_safe_sleep, async_safe_sleep
9
9
 
10
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
11
-
12
10
 
13
11
  async def async_retry_func(
14
12
  *,
@@ -6,8 +6,6 @@ import subprocess
6
6
 
7
7
  from pydantic import BaseModel
8
8
 
9
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
10
-
11
9
 
12
10
  class RunCmdResHasErr(Exception):
13
11
  pass
@@ -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 = ""
@@ -5,8 +5,6 @@ import math
5
5
  from datetime import timedelta
6
6
  from time import sleep
7
7
 
8
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
9
-
10
8
 
11
9
  def sync_safe_sleep(n: timedelta | float | int):
12
10
  if isinstance(n, timedelta):
@@ -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=10,
261
- max_overflow=10,
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=10,
274
- max_overflow=10,
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)})"
@@ -4,8 +4,6 @@ from typing import Optional, Any
4
4
 
5
5
  from arpakitlib.ar_type_util import raise_for_type
6
6
 
7
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
8
-
9
7
 
10
8
  def str_in(string: str, main_string: str, *, max_diff: Optional[int] = None) -> bool:
11
9
  if string not in main_string:
@@ -1,8 +1,6 @@
1
1
  # arpakit
2
2
  from typing import Optional, Any
3
3
 
4
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
5
-
6
4
 
7
5
  class NotSet:
8
6
  pass
@@ -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_=3,
50
+ max_tries_=1,
51
51
  raise_for_status_=True,
52
- timeout_=timedelta(seconds=3),
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_=3,
72
+ max_tries_=1,
73
73
  raise_for_status_=True,
74
74
  not_raise_for_statuses_=not_raise_for_statuses_,
75
- timeout_=timedelta(seconds=3),
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.6"
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