arpakitlib 1.6.46__py3-none-any.whl → 1.7.89__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 (158) hide show
  1. arpakitlib/_arpakit_project_template/.gitignore +51 -0
  2. arpakitlib/_arpakit_project_template/.python-version +1 -0
  3. arpakitlib/_arpakit_project_template/ARPAKITLIB +1 -0
  4. arpakitlib/_arpakit_project_template/AUTHOR.md +4 -0
  5. arpakitlib/{LICENSE → _arpakit_project_template/LICENSE} +1 -1
  6. arpakitlib/_arpakit_project_template/NOTICE +16 -0
  7. arpakitlib/_arpakit_project_template/README.md +6 -0
  8. arpakitlib/_arpakit_project_template/example.env +22 -0
  9. arpakitlib/_arpakit_project_template/manage/__init__.py +0 -0
  10. arpakitlib/_arpakit_project_template/manage/docker_ps.sh +2 -0
  11. arpakitlib/_arpakit_project_template/manage/docker_ps_a.sh +2 -0
  12. arpakitlib/_arpakit_project_template/manage/docker_run_postgres_for_dev.sh +4 -0
  13. arpakitlib/_arpakit_project_template/manage/docker_start_postgres_for_dev.sh +2 -0
  14. arpakitlib/_arpakit_project_template/manage/docker_stop_postgres_for_dev.sh +2 -0
  15. arpakitlib/_arpakit_project_template/manage/example_nginx_proxy.nginx +14 -0
  16. arpakitlib/_arpakit_project_template/manage/example_poetry_arpakitlib.sh +1 -0
  17. arpakitlib/_arpakit_project_template/manage/example_pyproject.toml +18 -0
  18. arpakitlib/_arpakit_project_template/manage/example_systemd.service +12 -0
  19. arpakitlib/_arpakit_project_template/manage/git_branch.sh +2 -0
  20. arpakitlib/_arpakit_project_template/manage/git_commit.sh +3 -0
  21. arpakitlib/_arpakit_project_template/manage/git_push_arpakit_company_github_1.sh +4 -0
  22. arpakitlib/_arpakit_project_template/manage/git_push_arpakit_company_gitlab_1.sh +4 -0
  23. arpakitlib/_arpakit_project_template/manage/git_push_arpakit_github_1.sh +4 -0
  24. arpakitlib/_arpakit_project_template/manage/git_push_arpakit_gitlab_1.sh +4 -0
  25. arpakitlib/_arpakit_project_template/manage/git_remote_v.sh +2 -0
  26. arpakitlib/_arpakit_project_template/manage/git_set_arpakit_company_origin.sh +7 -0
  27. arpakitlib/_arpakit_project_template/manage/git_set_arpakit_origin.sh +7 -0
  28. arpakitlib/_arpakit_project_template/manage/git_status.sh +2 -0
  29. arpakitlib/_arpakit_project_template/manage/hello_world.py +6 -0
  30. arpakitlib/_arpakit_project_template/manage/json_beutify.py +10 -0
  31. arpakitlib/_arpakit_project_template/manage/logging_check.py +14 -0
  32. arpakitlib/_arpakit_project_template/manage/note/__init__.py +0 -0
  33. arpakitlib/_arpakit_project_template/manage/note/note_1.txt +0 -0
  34. arpakitlib/_arpakit_project_template/manage/note/note_2.txt +0 -0
  35. arpakitlib/_arpakit_project_template/manage/note/note_3.txt +0 -0
  36. arpakitlib/_arpakit_project_template/manage/note/note_4.txt +0 -0
  37. arpakitlib/_arpakit_project_template/manage/note/note_5.txt +0 -0
  38. arpakitlib/_arpakit_project_template/manage/poetry_add_plugin_export.sh +2 -0
  39. arpakitlib/_arpakit_project_template/manage/poetry_check.sh +2 -0
  40. arpakitlib/_arpakit_project_template/manage/poetry_clear_cache.sh +4 -0
  41. arpakitlib/_arpakit_project_template/manage/poetry_config_virtualenvs_in_project_true.sh +2 -0
  42. arpakitlib/_arpakit_project_template/manage/poetry_generate_requirements.txt.sh +1 -0
  43. arpakitlib/_arpakit_project_template/manage/poetry_install.sh +5 -0
  44. arpakitlib/_arpakit_project_template/manage/poetry_lock.sh +2 -0
  45. arpakitlib/_arpakit_project_template/manage/poetry_remove_and_add_arpakitlib.sh +7 -0
  46. arpakitlib/_arpakit_project_template/manage/poetry_show.sh +2 -0
  47. arpakitlib/_arpakit_project_template/manage/poetry_show_arpakitlib.sh +2 -0
  48. arpakitlib/_arpakit_project_template/manage/poetry_update.sh +6 -0
  49. arpakitlib/_arpakit_project_template/manage/poetry_update_arpakitlib.sh +5 -0
  50. arpakitlib/_arpakit_project_template/manage/requirements.txt +209 -0
  51. arpakitlib/_arpakit_project_template/manage/sandbox/__init__.py +0 -0
  52. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_1.py +14 -0
  53. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_2.py +14 -0
  54. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_3.py +14 -0
  55. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_4.py +14 -0
  56. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_5.py +14 -0
  57. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_6.py +14 -0
  58. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_7.py +14 -0
  59. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_8.sh +0 -0
  60. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_9.sh +0 -0
  61. arpakitlib/_arpakit_project_template/manage/settings_check.py +10 -0
  62. arpakitlib/_arpakit_project_template/manage/settings_generate_env_example.py +13 -0
  63. arpakitlib/_arpakit_project_template/manage/sqlalchemy_db_check_conn.py +11 -0
  64. arpakitlib/_arpakit_project_template/manage/sqlalchemy_db_init.py +11 -0
  65. arpakitlib/_arpakit_project_template/manage/sqlalchemy_db_reinit.py +11 -0
  66. arpakitlib/_arpakit_project_template/resource/__init__.py +0 -0
  67. arpakitlib/_arpakit_project_template/resource/static/__init__.py +0 -0
  68. arpakitlib/_arpakit_project_template/resource/static/healthcheck +1 -0
  69. arpakitlib/_arpakit_project_template/resource/static/helloworld +1 -0
  70. arpakitlib/_arpakit_project_template/src/__init__.py +0 -0
  71. arpakitlib/_arpakit_project_template/src/additional_model/__init__.py +0 -0
  72. arpakitlib/_arpakit_project_template/src/additional_model/additional_model.py +6 -0
  73. arpakitlib/_arpakit_project_template/src/api/__init__.py +0 -0
  74. arpakitlib/_arpakit_project_template/src/api/asgi.py +3 -0
  75. arpakitlib/_arpakit_project_template/src/api/auth.py +1 -0
  76. arpakitlib/_arpakit_project_template/src/api/const.py +13 -0
  77. arpakitlib/_arpakit_project_template/src/api/create_api_app.py +117 -0
  78. arpakitlib/_arpakit_project_template/src/api/event.py +20 -0
  79. arpakitlib/_arpakit_project_template/src/api/router/__init__.py +0 -0
  80. arpakitlib/_arpakit_project_template/src/api/router/main_router.py +9 -0
  81. arpakitlib/_arpakit_project_template/src/api/router/v1/__init__.py +0 -0
  82. arpakitlib/_arpakit_project_template/src/api/router/v1/get_api_error_info.py +27 -0
  83. arpakitlib/_arpakit_project_template/src/api/router/v1/main_router.py +11 -0
  84. arpakitlib/_arpakit_project_template/src/api/schema/__init__.py +0 -0
  85. arpakitlib/_arpakit_project_template/src/api/schema/v1/__init__.py +0 -0
  86. arpakitlib/_arpakit_project_template/src/api/schema/v1/in_.py +0 -0
  87. arpakitlib/_arpakit_project_template/src/api/schema/v1/out.py +6 -0
  88. arpakitlib/_arpakit_project_template/src/api/start_api_for_dev.py +17 -0
  89. arpakitlib/_arpakit_project_template/src/api/start_api_for_dev_with_reload.py +9 -0
  90. arpakitlib/_arpakit_project_template/src/api/transmitted_api_data.py +9 -0
  91. arpakitlib/_arpakit_project_template/src/api/util.py +0 -0
  92. arpakitlib/_arpakit_project_template/src/business_service/__init__.py +0 -0
  93. arpakitlib/_arpakit_project_template/src/core/__init__.py +0 -0
  94. arpakitlib/_arpakit_project_template/src/core/const.py +48 -0
  95. arpakitlib/_arpakit_project_template/src/core/settings.py +86 -0
  96. arpakitlib/_arpakit_project_template/src/core/util.py +58 -0
  97. arpakitlib/_arpakit_project_template/src/db/__init__.py +0 -0
  98. arpakitlib/_arpakit_project_template/src/db/sqlalchemy_model.py +8 -0
  99. arpakitlib/_arpakit_project_template/src/db/util.py +21 -0
  100. arpakitlib/_arpakit_project_template/src/operation_execution/__init__.py +0 -0
  101. arpakitlib/_arpakit_project_template/src/operation_execution/const.py +9 -0
  102. arpakitlib/_arpakit_project_template/src/operation_execution/operation_executor.py +14 -0
  103. arpakitlib/_arpakit_project_template/src/operation_execution/scheduled_operations.py +25 -0
  104. arpakitlib/_arpakit_project_template/src/operation_execution/start_operation_executor_worker_for_dev.py +18 -0
  105. arpakitlib/_arpakit_project_template/src/operation_execution/start_scheduled_operation_creator_worker_for_dev.py +17 -0
  106. arpakitlib/_arpakit_project_template/src/operation_execution/util.py +21 -0
  107. arpakitlib/_arpakit_project_template/src/test_data/__init__.py +0 -0
  108. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_1.py +6 -0
  109. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_2.py +6 -0
  110. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_3.py +6 -0
  111. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_4.py +6 -0
  112. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_5.py +6 -0
  113. arpakitlib/_arpakit_project_template/src/util/__init__.py +0 -0
  114. arpakitlib/api_key_util.py +21 -0
  115. arpakitlib/ar_additional_model_util.py +25 -2
  116. arpakitlib/ar_aiogram_util.py +10 -18
  117. arpakitlib/ar_arpakit_lib_module_util.py +6 -1
  118. arpakitlib/ar_arpakit_project_template_util.py +96 -0
  119. arpakitlib/ar_arpakit_schedule_uust_api_client_util.py +24 -3
  120. arpakitlib/ar_arpakitlib_cli_util.py +79 -0
  121. arpakitlib/ar_base_worker_util.py +95 -48
  122. arpakitlib/ar_dream_ai_api_client_util.py +26 -52
  123. arpakitlib/ar_enumeration_util.py +11 -0
  124. arpakitlib/ar_exception_util.py +18 -0
  125. arpakitlib/ar_fastapi_static/healthcheck +1 -0
  126. arpakitlib/ar_fastapi_util.py +270 -137
  127. arpakitlib/ar_file_util.py +22 -0
  128. arpakitlib/ar_func_util.py +55 -0
  129. arpakitlib/ar_http_request_util.py +35 -6
  130. arpakitlib/ar_json_util.py +13 -7
  131. arpakitlib/ar_logging_util.py +5 -2
  132. arpakitlib/ar_need_type_util.py +12 -2
  133. arpakitlib/{ar_openai_util.py → ar_openai_api_client_util.py} +16 -2
  134. arpakitlib/ar_operation_execution_util.py +250 -105
  135. arpakitlib/ar_parse_command.py +25 -7
  136. arpakitlib/ar_schedule_uust_api_client_util.py +37 -23
  137. arpakitlib/ar_settings_util.py +37 -11
  138. arpakitlib/ar_sleep_util.py +0 -13
  139. arpakitlib/ar_sqlalchemy_model_util.py +35 -10
  140. arpakitlib/ar_sqlalchemy_util.py +4 -3
  141. arpakitlib/{ar_ssh_util.py → ar_ssh_runner_util.py} +2 -2
  142. arpakitlib/ar_str_util.py +43 -2
  143. arpakitlib/ar_type_util.py +68 -4
  144. arpakitlib/ar_yookassa_api_client_util.py +26 -44
  145. {arpakitlib-1.6.46.dist-info → arpakitlib-1.7.89.dist-info}/LICENSE +1 -1
  146. {arpakitlib-1.6.46.dist-info → arpakitlib-1.7.89.dist-info}/METADATA +17 -8
  147. arpakitlib-1.7.89.dist-info/NOTICE +16 -0
  148. arpakitlib-1.7.89.dist-info/RECORD +186 -0
  149. arpakitlib-1.7.89.dist-info/entry_points.txt +3 -0
  150. arpakitlib/AUTHOR.md +0 -7
  151. arpakitlib/NOTICE +0 -2
  152. arpakitlib/README.md +0 -7
  153. arpakitlib/ar_arpakitlib_info.py +0 -13
  154. arpakitlib/ar_generate_env_example.py +0 -22
  155. arpakitlib-1.6.46.dist-info/NOTICE +0 -2
  156. arpakitlib-1.6.46.dist-info/RECORD +0 -71
  157. /arpakitlib/{ar_zabbix_util.py → ar_zabbix_api_client_util.py} +0 -0
  158. {arpakitlib-1.6.46.dist-info → arpakitlib-1.7.89.dist-info}/WHEEL +0 -0
@@ -3,14 +3,14 @@
3
3
  import asyncio
4
4
  import hashlib
5
5
  import logging
6
- from datetime import datetime, timedelta
6
+ from datetime import datetime
7
7
  from typing import Any
8
8
 
9
9
  import pytz
10
+ from aiohttp import ClientResponse
10
11
 
11
12
  from arpakitlib.ar_dict_util import combine_dicts
12
13
  from arpakitlib.ar_http_request_util import async_make_http_request
13
- from arpakitlib.ar_type_util import raise_for_type
14
14
 
15
15
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
16
16
 
@@ -72,25 +72,25 @@ class ScheduleUUSTAPIClient:
72
72
  def generate_v2_token(self) -> str:
73
73
  return self.generate_new_v2_token(password_first_part=self.api_password_first_part)
74
74
 
75
- async def _async_make_http_get_request(
75
+ async def _async_make_http_request(
76
76
  self,
77
77
  *,
78
+ method: str = "GET",
78
79
  url: str,
79
- params: dict | None = None
80
- ) -> dict[str, Any]:
80
+ params: dict[str, Any] | None = None
81
+ ) -> ClientResponse:
81
82
  response = await async_make_http_request(
83
+ method=method,
82
84
  url=url,
83
- method="GET",
85
+ headers=self.headers,
84
86
  params=combine_dicts(params, self.auth_params()),
85
87
  proxy_url_=self.api_proxy_url,
86
- max_tries_=9,
87
- timeout_=timedelta(seconds=15),
88
- raise_for_status_=True,
89
- headers=self.headers
88
+ raise_for_status_=True
90
89
  )
91
90
  json_data = await response.json()
92
- raise_for_type(json_data, dict)
93
- return json_data
91
+ if "error" in json_data.keys():
92
+ raise Exception(f"error in json_data, {json_data}")
93
+ return response
94
94
 
95
95
  async def get_current_week(self) -> int:
96
96
  """
@@ -100,10 +100,11 @@ class ScheduleUUSTAPIClient:
100
100
  }
101
101
  """
102
102
 
103
- json_data = await self._async_make_http_get_request(
103
+ response = await self._async_make_http_request(
104
104
  url=self.api_url,
105
105
  params={"ask": "get_current_week"}
106
106
  )
107
+ json_data = await response.json()
107
108
  return json_data["data"][0]
108
109
 
109
110
  async def get_current_semester(self) -> str:
@@ -114,10 +115,11 @@ class ScheduleUUSTAPIClient:
114
115
  }
115
116
  """
116
117
 
117
- json_data = await self._async_make_http_get_request(
118
+ response = await self._async_make_http_request(
118
119
  url=self.api_url,
119
120
  params={"ask": "get_current_semestr"}
120
121
  )
122
+ json_data = await response.json()
121
123
  return json_data["data"][0]
122
124
 
123
125
  async def get_groups(self) -> list[dict[str, Any]]:
@@ -135,10 +137,11 @@ class ScheduleUUSTAPIClient:
135
137
  }
136
138
  """
137
139
 
138
- json_data = await self._async_make_http_get_request(
140
+ response = await self._async_make_http_request(
139
141
  url=self.api_url,
140
142
  params={"ask": "get_group_list"}
141
143
  )
144
+ json_data = await response.json()
142
145
  return list(json_data["data"].values())
143
146
 
144
147
  async def get_group_lessons(self, group_id: int, semester: str | None = None) -> list[dict[str, Any]]:
@@ -148,45 +151,56 @@ class ScheduleUUSTAPIClient:
148
151
  }
149
152
  if semester is not None:
150
153
  params["semester"] = semester
151
- json_data = await self._async_make_http_get_request(
154
+ response = await self._async_make_http_request(
152
155
  url=self.api_url,
153
156
  params=params
154
157
  )
158
+ json_data = await response.json()
155
159
  return json_data["data"]
156
160
 
157
161
  async def get_teachers(self) -> list[dict[str, Any]]:
158
- json_data = await self._async_make_http_get_request(
162
+ response = await self._async_make_http_request(
159
163
  url=self.api_url,
160
164
  params={"ask": "get_teacher_list"}
161
165
  )
166
+ json_data = await response.json()
162
167
  return list(json_data["data"].values())
163
168
 
164
169
  async def get_teacher_lessons(self, teacher_id: int, semester: str | None = None) -> list[dict[str, Any]]:
165
170
  params = {"ask": "get_teacher_schedule", "id": teacher_id}
166
171
  if semester is not None:
167
172
  params["semester"] = semester
168
- json_data = await self._async_make_http_get_request(
173
+ response = await self._async_make_http_request(
169
174
  url=self.api_url,
170
175
  params=params
171
176
  )
177
+ json_data = await response.json()
172
178
  return json_data["data"]
173
179
 
174
180
  async def check_conn(self):
175
181
  await self.get_current_week()
182
+ self._logger.info(f"connection is good")
176
183
 
177
184
  async def is_conn_good(self):
178
185
  try:
179
186
  await self.check_conn()
180
187
  except Exception as e:
181
- self._logger.error(e)
188
+ self._logger.error(f"connection is bad", exc_info=e)
182
189
  return False
183
190
  return True
184
191
 
185
192
  async def check_all(self):
186
- await self.get_groups()
187
- await self.get_teachers()
188
- await self.get_current_semester()
189
- await self.get_current_week()
193
+ groups = await self.get_groups()
194
+ self._logger.info(f"groups len: {len(groups)}")
195
+
196
+ teachers = await self.get_teachers()
197
+ self._logger.info(f"teachers len: {len(teachers)}")
198
+
199
+ current_semester = await self.get_current_semester()
200
+ self._logger.info(f"current_semester: {current_semester}")
201
+
202
+ current_week = await self.get_current_week()
203
+ self._logger.info(f"current_week: {current_week}")
190
204
 
191
205
 
192
206
  def __example():
@@ -1,19 +1,34 @@
1
+ # arpakit
2
+
3
+ from typing import Union
4
+
1
5
  from pydantic import ConfigDict, field_validator
6
+ from pydantic_core import PydanticUndefined
2
7
  from pydantic_settings import BaseSettings
3
8
 
4
9
  from arpakitlib.ar_enumeration_util import Enumeration
5
- from arpakitlib.ar_generate_env_example import generate_env_example
10
+
11
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
12
+
13
+
14
+ def generate_env_example(settings_class: Union[BaseSettings, type[BaseSettings]]):
15
+ res = ""
16
+ for k, f in settings_class.model_fields.items():
17
+ if f.default is not PydanticUndefined:
18
+ res += f"# {k}=\n"
19
+ else:
20
+ res += f"{k}=\n"
21
+ return res
6
22
 
7
23
 
8
24
  class SimpleSettings(BaseSettings):
9
25
  model_config = ConfigDict(extra="ignore")
10
26
 
11
27
  class ModeTypes(Enumeration):
12
- local: str = "local"
13
- test: str = "preprod"
28
+ not_prod: str = "not_prod"
14
29
  prod: str = "prod"
15
30
 
16
- mode_type: str = ModeTypes.local
31
+ mode_type: str = ModeTypes.not_prod
17
32
 
18
33
  @field_validator("mode_type")
19
34
  @classmethod
@@ -22,17 +37,28 @@ class SimpleSettings(BaseSettings):
22
37
  return v
23
38
 
24
39
  @property
25
- def is_mode_type_local(self) -> bool:
26
- return self.mode_type == self.ModeTypes.local
27
-
28
- @property
29
- def is_mode_type_test(self) -> bool:
30
- return self.mode_type == self.ModeTypes.test
40
+ def is_mode_type_not_prod(self) -> bool:
41
+ return self.mode_type == self.ModeTypes.not_prod
31
42
 
32
43
  @property
33
44
  def is_mode_type_prod(self) -> bool:
34
45
  return self.mode_type == self.ModeTypes.prod
35
46
 
36
47
  @classmethod
37
- def env_example(cls) -> str:
48
+ def generate_env_example(cls) -> str:
38
49
  return generate_env_example(settings_class=cls)
50
+
51
+ @classmethod
52
+ def save_env_example_to_file(cls, filepath: str) -> str:
53
+ env_example = cls.generate_env_example()
54
+ with open(filepath, mode="w") as f:
55
+ f.write(env_example)
56
+ return env_example
57
+
58
+
59
+ def __example():
60
+ pass
61
+
62
+
63
+ if __name__ == '__main__':
64
+ __example()
@@ -1,7 +1,6 @@
1
1
  # arpakit
2
2
 
3
3
  import asyncio
4
- import logging
5
4
  import math
6
5
  from time import sleep
7
6
 
@@ -9,12 +8,8 @@ from asyncpg.pgproto.pgproto import timedelta
9
8
 
10
9
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
11
10
 
12
- _logger = logging.getLogger(__name__)
13
-
14
11
 
15
12
  def sync_safe_sleep(n: timedelta | float | int):
16
- _logger.info(f"sync_safe_sleep ({n}) starts")
17
-
18
13
  if isinstance(n, timedelta):
19
14
  n = n.total_seconds()
20
15
  elif isinstance(n, int):
@@ -31,12 +26,8 @@ def sync_safe_sleep(n: timedelta | float | int):
31
26
  sleep(1)
32
27
  sleep(frac)
33
28
 
34
- _logger.info(f"sync_safe_sleep ({n}) ends")
35
-
36
29
 
37
30
  async def async_safe_sleep(n: timedelta | float | int):
38
- _logger.info(f"async_safe_sleep ({n}) starts")
39
-
40
31
  if isinstance(n, timedelta):
41
32
  n = n.total_seconds()
42
33
  elif isinstance(n, int):
@@ -48,11 +39,7 @@ async def async_safe_sleep(n: timedelta | float | int):
48
39
 
49
40
  n: float = n
50
41
 
51
- _logger.info(f"sleep_time ({n}) starts")
52
42
  await asyncio.sleep(n)
53
- _logger.info(f"sleep_time ({n}) ends")
54
-
55
- _logger.info(f"async_safe_sleep ({n}) ends")
56
43
 
57
44
 
58
45
  def __example():
@@ -10,11 +10,19 @@ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
10
10
 
11
11
  from arpakitlib.ar_datetime_util import now_utc_dt
12
12
  from arpakitlib.ar_enumeration_util import Enumeration
13
- from arpakitlib.ar_json_util import safely_transfer_to_json_str
13
+ from arpakitlib.ar_json_util import safely_transfer_obj_to_json_str
14
14
 
15
15
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
16
16
 
17
17
 
18
+ def generate_default_long_id():
19
+ return (
20
+ f"longid"
21
+ f"{str(uuid4()).replace('-', '')}"
22
+ f"{str(now_utc_dt().timestamp()).replace('.', '')}"
23
+ )
24
+
25
+
18
26
  class BaseDBM(DeclarativeBase):
19
27
  __abstract__ = True
20
28
  _bus_data: dict[str, Any] | None = None
@@ -26,17 +34,29 @@ class BaseDBM(DeclarativeBase):
26
34
  return self._bus_data
27
35
 
28
36
  def simple_dict(self, *, include_sd_properties: bool = True) -> dict[str, Any]:
29
- res = {c.key: getattr(self, c.key) for c in inspect(self).mapper.column_attrs}
37
+ res = {}
38
+
39
+ for c in inspect(self).mapper.column_attrs:
40
+ value = getattr(self, c.key)
41
+ if isinstance(value, BaseDBM):
42
+ res[c.key] = value.simple_dict(include_sd_properties=include_sd_properties)
43
+ else:
44
+ res[c.key] = value
30
45
 
31
46
  if include_sd_properties:
32
47
  for attr_name in dir(self):
33
48
  if attr_name.startswith("sdp_") and isinstance(getattr(type(self), attr_name, None), property):
34
- res[attr_name.removesuffix("sdp_")] = getattr(self, attr_name)
49
+ prop_name = attr_name.removeprefix("sdp_")
50
+ value = getattr(self, attr_name)
51
+ if isinstance(value, BaseDBM):
52
+ res[prop_name] = value.simple_dict(include_sd_properties=include_sd_properties)
53
+ else:
54
+ res[prop_name] = value
35
55
 
36
56
  return res
37
57
 
38
58
  def simple_json(self, *, include_sd_properties: bool = True) -> str:
39
- return safely_transfer_to_json_str(self.simple_dict(include_sd_properties=include_sd_properties))
59
+ return safely_transfer_obj_to_json_str(self.simple_dict(include_sd_properties=include_sd_properties))
40
60
 
41
61
 
42
62
  class SimpleDBM(BaseDBM):
@@ -46,7 +66,7 @@ class SimpleDBM(BaseDBM):
46
66
  INTEGER, primary_key=True, autoincrement=True, sort_order=-3, nullable=False
47
67
  )
48
68
  long_id: Mapped[str] = mapped_column(
49
- TEXT, insert_default=uuid4, unique=True, sort_order=-2, nullable=False
69
+ TEXT, insert_default=generate_default_long_id, unique=True, sort_order=-2, nullable=False
50
70
  )
51
71
  creation_dt: Mapped[datetime] = mapped_column(
52
72
  TIMESTAMP(timezone=True), insert_default=now_utc_dt, index=True, sort_order=-1, nullable=False
@@ -73,6 +93,11 @@ class StoryLogDBM(SimpleDBM):
73
93
  )
74
94
 
75
95
 
96
+ class BaseOperationTypes(Enumeration):
97
+ healthcheck_ = "healthcheck"
98
+ raise_fake_exception_ = "raise_fake_exception"
99
+
100
+
76
101
  class OperationDBM(SimpleDBM):
77
102
  __tablename__ = "operation"
78
103
 
@@ -82,16 +107,12 @@ class OperationDBM(SimpleDBM):
82
107
  executed_without_error = "executed_without_error"
83
108
  executed_with_error = "executed_with_error"
84
109
 
85
- class Types(Enumeration):
86
- healthcheck_ = "healthcheck"
87
- raise_fake_exception_ = "raise_fake_exception"
88
-
89
110
  status: Mapped[str] = mapped_column(
90
111
  TEXT, index=True, insert_default=Statuses.waiting_for_execution,
91
112
  server_default=Statuses.waiting_for_execution, nullable=False
92
113
  )
93
114
  type: Mapped[str] = mapped_column(
94
- TEXT, index=True, insert_default=Types.healthcheck_, nullable=False
115
+ TEXT, index=True, insert_default=BaseOperationTypes.healthcheck_, nullable=False
95
116
  )
96
117
  execution_start_dt: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True), nullable=True)
97
118
  execution_finish_dt: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True), nullable=True)
@@ -128,6 +149,10 @@ class OperationDBM(SimpleDBM):
128
149
  return None
129
150
  return self.duration.total_seconds()
130
151
 
152
+ @property
153
+ def sdp_duration_total_seconds(self) -> float | None:
154
+ return self.duration_total_seconds
155
+
131
156
 
132
157
  def __example():
133
158
  pass
@@ -26,9 +26,10 @@ class SQLAlchemyDB:
26
26
  self,
27
27
  *,
28
28
  db_url: str = "postgresql://arpakitlib:arpakitlib@localhost:50629/arpakitlib",
29
- echo: bool = False,
29
+ db_echo: bool = False,
30
30
  need_include_operation_dbm: bool = False,
31
- need_include_story_dbm: bool = False
31
+ need_include_story_dbm: bool = False,
32
+ db_models: list[Any] | None = None
32
33
  ):
33
34
  self._logger = logging.getLogger(self.__class__.__name__)
34
35
  self.need_include_operation_dbm = need_include_operation_dbm
@@ -37,7 +38,7 @@ class SQLAlchemyDB:
37
38
  self.need_include_story_dbm = True
38
39
  self.engine = create_engine(
39
40
  url=db_url,
40
- echo=echo,
41
+ echo=db_echo,
41
42
  pool_size=5,
42
43
  max_overflow=10,
43
44
  poolclass=QueuePool,
@@ -11,7 +11,7 @@ import asyncssh
11
11
  import paramiko
12
12
  from pydantic import BaseModel
13
13
 
14
- from arpakitlib.ar_json_util import safely_transfer_to_json_str
14
+ from arpakitlib.ar_json_util import safely_transfer_obj_to_json_str
15
15
 
16
16
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
17
17
 
@@ -61,7 +61,7 @@ class SSHRunRes(BaseModel):
61
61
  }
62
62
 
63
63
  def simple_json(self) -> str:
64
- return safely_transfer_to_json_str(self.simple_dict())
64
+ return safely_transfer_obj_to_json_str(self.simple_dict())
65
65
 
66
66
  def __repr__(self) -> str:
67
67
  return self.simple_json()
arpakitlib/ar_str_util.py CHANGED
@@ -52,12 +52,18 @@ def bidirectional_str_startswith(string1: str, string2: str, max_diff: Optional[
52
52
  return False
53
53
 
54
54
 
55
- def blank_if_none(string: Optional[str] = None) -> str:
55
+ def make_blank_if_none(string: Optional[str] = None) -> str:
56
56
  if string is None:
57
57
  return ""
58
58
  return string
59
59
 
60
60
 
61
+ def make_none_if_blank(string: Optional[str] = None) -> str | None:
62
+ if not string:
63
+ return None
64
+ return string
65
+
66
+
61
67
  def remove_html(string: str) -> str:
62
68
  raise_for_type(string, str)
63
69
  return BeautifulSoup(string, "html.parser").text
@@ -73,8 +79,43 @@ def remove_tags_and_html(string: str) -> str:
73
79
  return remove_tags(remove_html(string))
74
80
 
75
81
 
82
+ def raise_if_string_blank(string: str) -> str:
83
+ if not string:
84
+ raise ValueError("not string")
85
+ return string
86
+
87
+
76
88
  def __example():
77
- pass
89
+ print("str_in:")
90
+ print(str_in(string="hello", main_string="hello world")) # True
91
+ print(str_in(string="bye", main_string="hello world")) # False
92
+ print(str_in(string="hello", main_string="hello world", max_diff=6)) # True
93
+ print(str_in(string="hello", main_string="hello world", max_diff=1)) # False
94
+
95
+ print("\nbidirectional_str_in:")
96
+ print(bidirectional_str_in(string1="hello", string2="hello world")) # True
97
+ print(bidirectional_str_in(string1="world", string2="hello world")) # True
98
+
99
+ print("\nstr_startswith:")
100
+ print(str_startswith(string="hello", main_string="hello world")) # True
101
+ print(str_startswith(string="world", main_string="hello world")) # False
102
+
103
+ print("\nbidirectional_str_startswith:")
104
+ print(bidirectional_str_startswith(string1="hello", string2="hello world")) # True
105
+ print(bidirectional_str_startswith(string1="world", string2="hello world")) # False
106
+
107
+ print("\nmake blank_if_none:")
108
+ print(make_blank_if_none()) # ""
109
+ print(make_blank_if_none(string="test")) # "test"
110
+
111
+ print("\nremove_html:")
112
+ print(remove_html(string="<div>Hello <b>World</b></div>")) # "Hello World"
113
+
114
+ print("\nremove_tags:")
115
+ print(remove_tags(string="<div>Hello <b>World</b></div>")) # "divHello bWorldbdiv"
116
+
117
+ print("\nremove_tags_and_html:")
118
+ print(remove_tags_and_html("<div>Hello <b>World</b></div>")) # "Hello World"
78
119
 
79
120
 
80
121
  if __name__ == '__main__':
@@ -67,13 +67,77 @@ def raise_for_types(comparable, need_types, comment_for_error: Optional[str] = N
67
67
  raise TypeError(err)
68
68
 
69
69
 
70
- def raise_if_not_async_func(func: Any):
71
- if not inspect.iscoroutinefunction(func):
72
- raise TypeError(f"The provided function '{func.__name__}' is not an async function")
70
+ def make_none_to_false(v: Any) -> Any:
71
+ if v is None:
72
+ return False
73
+ return v
74
+
75
+
76
+ def raise_if_none(v: Any) -> Any:
77
+ if v is None:
78
+ raise ValueError(f"v is None, v={v}, type(v)={type(v)}")
79
+ return v
80
+
81
+
82
+ def raise_if_not_none(v: Any) -> Any:
83
+ if v is not None:
84
+ raise ValueError(f"v is not None, v={v}, type(v)={type(v)}")
85
+ return v
73
86
 
74
87
 
75
88
  def __example():
76
- pass
89
+ print("is_set:")
90
+ print(is_set(v=NotSet)) # False
91
+ print(is_set(v="hello world")) # True
92
+
93
+ print("\nis_not_set:")
94
+ print(is_not_set(v=NotSet)) # True
95
+ print(is_not_set(v="hello world")) # False
96
+
97
+ print("\nis_set_and_not_none:")
98
+ print(is_set_and_not_none(v=NotSet)) # False
99
+ print(is_set_and_not_none(v=None)) # False
100
+ print(is_set_and_not_none(v=1000)) # True
101
+
102
+ print("\nis_not_set_or_none:")
103
+ print(is_not_set_or_none(v=NotSet)) # True
104
+ print(is_not_set_or_none(v=None)) # True
105
+ print(is_not_set_or_none(v=100)) # False
106
+
107
+ print("\nmake_none_if_not_set:")
108
+ print(make_none_if_not_set(v=NotSet)) # None
109
+ print(make_none_if_not_set(v="hello world")) # hello world
110
+
111
+ print("\nmake_none_to_false:")
112
+ print(make_none_to_false(v=None)) # False
113
+ print(make_none_to_false(v=True)) # True
114
+ print(make_none_to_false(v=100)) # 100
115
+
116
+ print("\nraise_if_set:")
117
+ try:
118
+ raise_if_set(v=100) # raise
119
+ except ValueError as e:
120
+ print(e)
121
+
122
+ print("\nraise_if_set:")
123
+ try:
124
+ raise_if_not_set(v=NotSet) # raise
125
+ except ValueError as e:
126
+ print(e)
127
+
128
+ print("\nraise_for_type:")
129
+ try:
130
+ raise_for_type(comparable="test", need_type=str) # pass
131
+ raise_for_type(comparable=100, need_type=str) # raise
132
+ except TypeError as e:
133
+ print(e)
134
+
135
+ print("\nraise_for_types:")
136
+ try:
137
+ raise_for_types(comparable="test", need_types=[str, int]) # pass
138
+ raise_for_types(comparable=100.5, need_types=[str, int], comment_for_error="Ooops") # raise
139
+ except TypeError as e:
140
+ print(e)
77
141
 
78
142
 
79
143
  if __name__ == '__main__':