arpakitlib 1.7.66__py3-none-any.whl → 1.7.124__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 (81) hide show
  1. arpakitlib/_arpakit_project_template/example.env +4 -0
  2. arpakitlib/_arpakit_project_template/manage/hello_world.py +2 -2
  3. arpakitlib/_arpakit_project_template/manage/json_beutify.py +4 -4
  4. arpakitlib/_arpakit_project_template/manage/poetry_config.sh +2 -0
  5. arpakitlib/_arpakit_project_template/manage/poetry_self_add_plugin_export.sh +2 -0
  6. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_1.py +4 -4
  7. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_2.py +4 -4
  8. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_3.py +4 -4
  9. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_4.py +4 -4
  10. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_5.py +4 -4
  11. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_6.py +4 -4
  12. arpakitlib/_arpakit_project_template/manage/sandbox/sandbox_7.py +4 -4
  13. arpakitlib/_arpakit_project_template/resource/static/healthcheck +1 -0
  14. arpakitlib/_arpakit_project_template/src/admin1/__init__.py +0 -0
  15. arpakitlib/_arpakit_project_template/src/admin1/add_admin_in_app.py +25 -0
  16. arpakitlib/_arpakit_project_template/src/admin1/admin_auth.py +29 -0
  17. arpakitlib/_arpakit_project_template/src/admin1/model_view.py +19 -0
  18. arpakitlib/_arpakit_project_template/src/api/auth.py +1 -6
  19. arpakitlib/_arpakit_project_template/src/api/create_api_app.py +13 -52
  20. arpakitlib/_arpakit_project_template/src/api/event.py +51 -2
  21. arpakitlib/_arpakit_project_template/src/api/router/main_router.py +3 -0
  22. arpakitlib/_arpakit_project_template/src/api/router/v1/get_api_error_info.py +6 -4
  23. arpakitlib/_arpakit_project_template/src/api/start_api_for_dev_with_reload.py +12 -4
  24. arpakitlib/_arpakit_project_template/src/api/{start_api_for_dev.py → start_api_for_dev_without_reload.py} +3 -3
  25. arpakitlib/_arpakit_project_template/src/api/transmitted_api_data.py +4 -0
  26. arpakitlib/_arpakit_project_template/src/business_service/hello_world.py +12 -0
  27. arpakitlib/_arpakit_project_template/{manage/logging_check.py → src/core/check_logging.py} +3 -3
  28. arpakitlib/_arpakit_project_template/src/core/check_settings.py +12 -0
  29. arpakitlib/_arpakit_project_template/src/core/generate_settings_env_example.py +16 -0
  30. arpakitlib/_arpakit_project_template/src/core/settings.py +13 -5
  31. arpakitlib/_arpakit_project_template/src/core/util.py +0 -18
  32. arpakitlib/_arpakit_project_template/{manage/sqlalchemy_db_check_conn.py → src/db/check_conn_sqlalchemy_db.py} +2 -1
  33. arpakitlib/_arpakit_project_template/src/db/const.py +0 -0
  34. arpakitlib/_arpakit_project_template/src/db/init_sqlalchemy_db.py +11 -0
  35. arpakitlib/_arpakit_project_template/src/db/reinit_sqlalchemy_db.py +13 -0
  36. arpakitlib/_arpakit_project_template/src/db/util.py +21 -0
  37. arpakitlib/_arpakit_project_template/src/operation_execution/operation_executor.py +6 -4
  38. arpakitlib/_arpakit_project_template/src/operation_execution/scheduled_operations.py +3 -3
  39. arpakitlib/_arpakit_project_template/src/operation_execution/{start_operation_executor_worker_for_dev.py → start_operation_executor_worker.py} +7 -5
  40. arpakitlib/_arpakit_project_template/src/operation_execution/start_scheduled_operation_creator_worker.py +19 -0
  41. arpakitlib/_arpakit_project_template/src/operation_execution/util.py +0 -0
  42. arpakitlib/_arpakit_project_template/src/tg_bot/__init__.py +0 -0
  43. arpakitlib/_arpakit_project_template/src/tg_bot/router/__init__.py +0 -0
  44. arpakitlib/_arpakit_project_template/src/tg_bot/start_tg_bot.py +0 -0
  45. arpakitlib/api_key_util.py +12 -0
  46. arpakitlib/ar_additional_model_util.py +18 -1
  47. arpakitlib/ar_arpakit_lib_module_util.py +13 -1
  48. arpakitlib/ar_arpakit_schedule_uust_api_client_util.py +24 -3
  49. arpakitlib/ar_arpakitlib_cli_util.py +2 -0
  50. arpakitlib/ar_base_worker_util.py +67 -18
  51. arpakitlib/ar_exception_util.py +13 -0
  52. arpakitlib/ar_fastapi_util.py +129 -98
  53. arpakitlib/ar_file_util.py +2 -0
  54. arpakitlib/ar_func_util.py +55 -0
  55. arpakitlib/ar_json_util.py +11 -9
  56. arpakitlib/ar_need_type_util.py +8 -1
  57. arpakitlib/ar_openai_api_client_util.py +16 -2
  58. arpakitlib/ar_operation_execution_util.py +143 -141
  59. arpakitlib/ar_schedule_uust_api_client_util.py +13 -6
  60. arpakitlib/ar_settings_util.py +24 -5
  61. arpakitlib/ar_sqlalchemy_model_util.py +37 -7
  62. arpakitlib/ar_ssh_runner_util.py +2 -2
  63. arpakitlib/ar_str_util.py +30 -1
  64. arpakitlib/ar_type_util.py +52 -7
  65. {arpakitlib-1.7.66.dist-info → arpakitlib-1.7.124.dist-info}/METADATA +27 -20
  66. {arpakitlib-1.7.66.dist-info → arpakitlib-1.7.124.dist-info}/RECORD +70 -62
  67. {arpakitlib-1.7.66.dist-info → arpakitlib-1.7.124.dist-info}/WHEEL +1 -1
  68. arpakitlib/_arpakit_project_template/AUTHOR.md +0 -4
  69. arpakitlib/_arpakit_project_template/manage/example_nginx_proxy.nginx +0 -14
  70. arpakitlib/_arpakit_project_template/manage/example_poetry_arpakitlib.sh +0 -1
  71. arpakitlib/_arpakit_project_template/manage/example_pyproject.toml +0 -18
  72. arpakitlib/_arpakit_project_template/manage/example_systemd.service +0 -12
  73. arpakitlib/_arpakit_project_template/manage/requirements.txt +0 -209
  74. arpakitlib/_arpakit_project_template/manage/settings_check.py +0 -10
  75. arpakitlib/_arpakit_project_template/manage/settings_generate_env_example.py +0 -13
  76. arpakitlib/_arpakit_project_template/manage/sqlalchemy_db_init.py +0 -10
  77. arpakitlib/_arpakit_project_template/manage/sqlalchemy_db_reinit.py +0 -10
  78. arpakitlib/_arpakit_project_template/src/operation_execution/start_scheduled_operation_creator_worker_for_dev.py +0 -16
  79. {arpakitlib-1.7.66.dist-info → arpakitlib-1.7.124.dist-info}/LICENSE +0 -0
  80. {arpakitlib-1.7.66.dist-info → arpakitlib-1.7.124.dist-info}/NOTICE +0 -0
  81. {arpakitlib-1.7.66.dist-info → arpakitlib-1.7.124.dist-info}/entry_points.txt +0 -0
@@ -1,13 +1,10 @@
1
1
  import asyncio
2
- import importlib
3
- from contextlib import suppress
4
2
  from datetime import datetime
5
3
  from functools import lru_cache
6
4
 
7
5
  from arpakitlib.ar_datetime_util import now_dt
8
6
  from arpakitlib.ar_file_storage_in_dir_util import FileStorageInDir
9
7
  from arpakitlib.ar_logging_util import setup_normal_logging
10
- from arpakitlib.ar_sqlalchemy_util import SQLAlchemyDB
11
8
  from arpakitlib.ar_type_util import raise_if_none
12
9
  from src.core.settings import get_cached_settings
13
10
 
@@ -43,21 +40,6 @@ def get_cached_dump_file_storage_in_dir() -> FileStorageInDir:
43
40
  return create_dump_file_storage_in_dir()
44
41
 
45
42
 
46
- def create_sqlalchemy_db() -> SQLAlchemyDB:
47
- with suppress(Exception):
48
- importlib.import_module("src.db.sqlalchemy_model")
49
-
50
- return SQLAlchemyDB(
51
- db_url=get_cached_settings().sql_db_url,
52
- db_echo=get_cached_settings().sql_db_echo
53
- )
54
-
55
-
56
- @lru_cache()
57
- def get_cached_sqlalchemy_db() -> SQLAlchemyDB:
58
- return create_sqlalchemy_db()
59
-
60
-
61
43
  def now_local_dt() -> datetime:
62
44
  raise_if_none(get_cached_settings().local_timezone_as_pytz)
63
45
  return now_dt(tz=get_cached_settings().local_timezone_as_pytz)
@@ -1,4 +1,5 @@
1
- from src.core.util import setup_logging, get_cached_sqlalchemy_db
1
+ from src.core.util import setup_logging
2
+ from src.db.util import get_cached_sqlalchemy_db
2
3
 
3
4
 
4
5
  def command():
File without changes
@@ -0,0 +1,11 @@
1
+ from src.core.util import setup_logging
2
+ from src.db.util import get_cached_sqlalchemy_db
3
+
4
+
5
+ def __init_sqlalchemy_db():
6
+ setup_logging()
7
+ get_cached_sqlalchemy_db().init()
8
+
9
+
10
+ if __name__ == '__main__':
11
+ __init_sqlalchemy_db()
@@ -0,0 +1,13 @@
1
+ from src.core.settings import get_cached_settings
2
+ from src.core.util import setup_logging
3
+ from src.db.util import get_cached_sqlalchemy_db
4
+
5
+
6
+ def __reinit_sqlalchemy_db():
7
+ setup_logging()
8
+ get_cached_settings().raise_if_mode_type_not_prod()
9
+ get_cached_sqlalchemy_db().reinit()
10
+
11
+
12
+ if __name__ == '__main__':
13
+ __reinit_sqlalchemy_db()
@@ -0,0 +1,21 @@
1
+ import importlib
2
+ from contextlib import suppress
3
+ from functools import lru_cache
4
+
5
+ from arpakitlib.ar_sqlalchemy_util import SQLAlchemyDB
6
+ from src.core.settings import get_cached_settings
7
+
8
+
9
+ def create_sqlalchemy_db() -> SQLAlchemyDB:
10
+ with suppress(Exception):
11
+ importlib.import_module("src.db.sqlalchemy_model")
12
+
13
+ return SQLAlchemyDB(
14
+ db_url=get_cached_settings().sql_db_url,
15
+ db_echo=get_cached_settings().sql_db_echo
16
+ )
17
+
18
+
19
+ @lru_cache()
20
+ def get_cached_sqlalchemy_db() -> SQLAlchemyDB:
21
+ return create_sqlalchemy_db()
@@ -1,14 +1,16 @@
1
+ from sqlalchemy.orm import Session
2
+
1
3
  from arpakitlib.ar_operation_execution_util import BaseOperationExecutor
2
4
  from arpakitlib.ar_sqlalchemy_model_util import OperationDBM
3
5
 
4
6
 
5
7
  class OperationExecutor(BaseOperationExecutor):
6
- def sync_execute_operation(self, operation_dbm: OperationDBM) -> OperationDBM:
8
+ def sync_execute_operation(self, operation_dbm: OperationDBM, session: Session) -> OperationDBM:
7
9
  # ...
8
- operation_dbm = super().sync_execute_operation(operation_dbm=operation_dbm)
10
+ operation_dbm = super().sync_execute_operation(operation_dbm=operation_dbm, session=session)
9
11
  return operation_dbm
10
12
 
11
- async def async_execute_operation(self, operation_dbm: OperationDBM) -> OperationDBM:
13
+ async def async_execute_operation(self, operation_dbm: OperationDBM, session: Session) -> OperationDBM:
12
14
  # ...
13
- operation_dbm = await super().async_execute_operation(operation_dbm=operation_dbm)
15
+ operation_dbm = await super().async_execute_operation(operation_dbm=operation_dbm, session=session)
14
16
  return operation_dbm
@@ -4,14 +4,14 @@ from arpakitlib.ar_operation_execution_util import ScheduledOperation, every_tim
4
4
  between_different_times_is_time_func
5
5
  from arpakitlib.ar_sqlalchemy_model_util import BaseOperationTypes
6
6
 
7
- ALL_SCHEDULED_OPERATIONS = []
7
+ SCHEDULED_OPERATIONS = []
8
8
 
9
9
  healthcheck_1_scheduled_operation = ScheduledOperation(
10
10
  type=BaseOperationTypes.healthcheck_,
11
11
  input_data={"healthcheck_1": "healthcheck_1"},
12
12
  is_time_func=every_timedelta_is_time_func(td=timedelta(seconds=15))
13
13
  )
14
- ALL_SCHEDULED_OPERATIONS.append(healthcheck_1_scheduled_operation)
14
+ SCHEDULED_OPERATIONS.append(healthcheck_1_scheduled_operation)
15
15
 
16
16
  healthcheck_2_scheduled_operation = ScheduledOperation(
17
17
  type=BaseOperationTypes.healthcheck_,
@@ -22,4 +22,4 @@ healthcheck_2_scheduled_operation = ScheduledOperation(
22
22
  ),
23
23
  timeout_after_creation=timedelta(seconds=60)
24
24
  )
25
- ALL_SCHEDULED_OPERATIONS.append(healthcheck_2_scheduled_operation)
25
+ SCHEDULED_OPERATIONS.append(healthcheck_2_scheduled_operation)
@@ -1,17 +1,19 @@
1
1
  from arpakitlib.ar_operation_execution_util import OperationExecutorWorker
2
- from src.core.util import get_cached_sqlalchemy_db, setup_logging
2
+ from src.core.settings import get_cached_settings
3
+ from src.core.util import setup_logging
4
+ from src.db.util import get_cached_sqlalchemy_db
3
5
  from src.operation_execution.operation_executor import OperationExecutor
4
6
 
5
7
 
6
- def start_operation_executor_worker_for_dev():
8
+ def start_operation_executor_worker():
7
9
  setup_logging()
10
+ get_cached_settings().raise_if_mode_type_prod()
8
11
  worker = OperationExecutorWorker(
9
12
  sqlalchemy_db=get_cached_sqlalchemy_db(),
10
- operation_executor=OperationExecutor(sqlalchemy_db=get_cached_sqlalchemy_db()),
11
- filter_operation_types=None
13
+ operation_executor=OperationExecutor(sqlalchemy_db=get_cached_sqlalchemy_db())
12
14
  )
13
15
  worker.sync_safe_run()
14
16
 
15
17
 
16
18
  if __name__ == '__main__':
17
- start_operation_executor_worker_for_dev()
19
+ start_operation_executor_worker()
@@ -0,0 +1,19 @@
1
+ from arpakitlib.ar_operation_execution_util import ScheduledOperationCreatorWorker
2
+ from src.core.settings import get_cached_settings
3
+ from src.core.util import setup_logging
4
+ from src.db.util import get_cached_sqlalchemy_db
5
+ from src.operation_execution.scheduled_operations import SCHEDULED_OPERATIONS
6
+
7
+
8
+ def start_scheduled_operation_creator_worker():
9
+ setup_logging()
10
+ get_cached_settings().raise_if_mode_type_prod()
11
+ worker = ScheduledOperationCreatorWorker(
12
+ sqlalchemy_db=get_cached_sqlalchemy_db(),
13
+ scheduled_operations=SCHEDULED_OPERATIONS
14
+ )
15
+ worker.sync_safe_run()
16
+
17
+
18
+ if __name__ == '__main__':
19
+ start_scheduled_operation_creator_worker()
@@ -2,8 +2,20 @@ from uuid import uuid4
2
2
 
3
3
  from arpakitlib.ar_datetime_util import now_utc_dt
4
4
 
5
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
+
5
7
 
6
8
  def generate_api_key() -> str:
7
9
  return (
8
10
  f"apikey{str(uuid4()).replace('-', '')}{str(now_utc_dt().timestamp()).replace('.', '')}"
9
11
  )
12
+
13
+
14
+ def __example():
15
+ for i in range(5):
16
+ api_key = generate_api_key()
17
+ print(f"API-key: {api_key}")
18
+
19
+
20
+ if __name__ == '__main__':
21
+ __example()
@@ -3,6 +3,8 @@ from typing import Any
3
3
 
4
4
  from pydantic import BaseModel, ConfigDict
5
5
 
6
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
7
+
6
8
 
7
9
  class BaseAM(BaseModel):
8
10
  model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True, from_attributes=True)
@@ -16,7 +18,22 @@ class BaseAM(BaseModel):
16
18
 
17
19
 
18
20
  def __example():
19
- pass
21
+ class UserAM(BaseAM):
22
+ id: int
23
+ name: str
24
+ email: str
25
+
26
+ @property
27
+ def bus_data_age(self) -> int | None:
28
+ return self.bus_data.get("age")
29
+
30
+ user = UserAM(id=1, name="John Doe", email="john.doe@example.com")
31
+ print(user.name) # John Doe
32
+
33
+ # bus_data
34
+ user.bus_data["age"] = 22
35
+ print(user.bus_data) # {'age': '22'}
36
+ print(user.bus_data_age) # 22
20
37
 
21
38
 
22
39
  if __name__ == '__main__':
@@ -79,6 +79,12 @@ class ArpakitLibModules(NamedTuple):
79
79
  if arpakit_lib_module.module_has_error
80
80
  ]
81
81
 
82
+ def have_modules_with_error(self) -> bool:
83
+ for arpakit_lib_module in self.arpakit_lib_modules:
84
+ if arpakit_lib_module.module_has_error:
85
+ return True
86
+ return False
87
+
82
88
  def module_name_to_module_exception(self, *, filter_module_has_error: bool = False) -> dict[str, BaseException]:
83
89
  if filter_module_has_error:
84
90
  return {
@@ -144,7 +150,13 @@ def get_arpakit_lib_modules() -> ArpakitLibModules:
144
150
 
145
151
 
146
152
  def __example():
147
- pass
153
+ for module_name, d in (
154
+ get_arpakit_lib_modules().module_name_to_module_version_and_module_has_errors().items()
155
+ ):
156
+ print(module_name)
157
+ print(d)
158
+ print()
159
+ print("have_modules_with_error", get_arpakit_lib_modules().have_modules_with_error())
148
160
 
149
161
 
150
162
  if __name__ == '__main__':
@@ -17,7 +17,7 @@ from pydantic import ConfigDict, BaseModel
17
17
 
18
18
  from arpakitlib.ar_dict_util import combine_dicts
19
19
  from arpakitlib.ar_enumeration_util import Enumeration
20
- from arpakitlib.ar_json_util import safely_transfer_to_json_str
20
+ from arpakitlib.ar_json_util import safely_transfer_obj_to_json_str
21
21
  from arpakitlib.ar_sleep_util import async_safe_sleep
22
22
  from arpakitlib.ar_type_util import raise_for_type
23
23
 
@@ -53,7 +53,7 @@ class BaseAPIModel(BaseModel):
53
53
  model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True, from_attributes=True)
54
54
 
55
55
  def simple_json(self) -> str:
56
- return safely_transfer_to_json_str(self.model_dump(mode="json"))
56
+ return safely_transfer_obj_to_json_str(self.model_dump(mode="json"))
57
57
 
58
58
 
59
59
  class GroupAPIModel(BaseAPIModel):
@@ -521,7 +521,28 @@ def __example():
521
521
 
522
522
 
523
523
  async def __async_example():
524
- pass
524
+ client = ARPAKITScheduleUUSTAPIClient(api_key="TEST_API_KEY", use_cache=True)
525
+
526
+ healthcheck = await client.healthcheck()
527
+ print(f"Healthcheck: {healthcheck}")
528
+
529
+ auth_healthcheck = await client.auth_healthcheck()
530
+ print(f"Auth Healthcheck: {auth_healthcheck}")
531
+
532
+ current_week = await client.get_current_week()
533
+ print(f"Текущая неделя: {current_week.simple_json() if current_week else 'Не найдено'}")
534
+
535
+ current_semester = await client.get_current_semester()
536
+ print(f"Текущий семестр: {current_semester.simple_json() if current_semester else 'Не найдено'}")
537
+
538
+ groups = await client.get_groups()
539
+ print(f"Группы: {[group.simple_json() for group in groups]}")
540
+
541
+ teachers = await client.get_teachers()
542
+ print(f"Преподаватели: {[teacher.simple_json() for teacher in teachers]}")
543
+
544
+ weather = await client.get_weather_in_ufa()
545
+ print(f"Погода в Уфе: {weather.simple_json()}")
525
546
 
526
547
 
527
548
  if __name__ == '__main__':
@@ -7,6 +7,8 @@ from arpakitlib.ar_need_type_util import parse_need_type, NeedTypes
7
7
  from arpakitlib.ar_parse_command import parse_command
8
8
  from arpakitlib.ar_str_util import raise_if_string_blank
9
9
 
10
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
11
+
10
12
 
11
13
  def execute_arpakitlib_cli(*, full_command: str | None = None):
12
14
  if full_command is None:
@@ -6,27 +6,58 @@ import multiprocessing
6
6
  import threading
7
7
  from abc import ABC
8
8
  from datetime import timedelta
9
+ from random import randint
10
+ from typing import Any
11
+ from uuid import uuid4
9
12
 
13
+ from arpakitlib.ar_datetime_util import now_utc_dt
10
14
  from arpakitlib.ar_enumeration_util import Enumeration
15
+ from arpakitlib.ar_func_util import is_async_function, is_sync_function
11
16
  from arpakitlib.ar_sleep_util import sync_safe_sleep, async_safe_sleep
12
17
 
13
18
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
14
19
 
15
20
 
16
21
  class BaseWorker(ABC):
17
- def __init__(self):
18
- self.worker_name = self.__class__.__name__
19
- self._logger = logging.getLogger(self.worker_name)
20
- self.timeout_after_run = timedelta(seconds=0.1).total_seconds()
21
- self.timeout_after_err_in_run = timedelta(seconds=1).total_seconds()
22
+ def __init__(
23
+ self,
24
+ *,
25
+ timeout_after_run=timedelta(seconds=0.3),
26
+ timeout_after_err_in_run=timedelta(seconds=1),
27
+ startup_funcs: list[Any] | None = None,
28
+ worker_name: str | None = None
29
+ ):
30
+ if startup_funcs is None:
31
+ startup_funcs = []
32
+ self.startup_funcs = startup_funcs
33
+ if worker_name is None:
34
+ worker_name = self.__class__.__name__
35
+ self.worker_name = worker_name
36
+ self.worker_creation_dt = now_utc_dt()
37
+ self.worker_id = f"{str(uuid4()).replace('-', '')}_{randint(1000, 99999)}"
38
+ self.worker_fullname = (
39
+ f"{self.worker_name}_{self.worker_creation_dt.isoformat()}_{self.worker_id}"
40
+ )
41
+ self._logger = logging.getLogger(self.worker_fullname)
42
+ self.timeout_after_run = timeout_after_run
43
+ self.timeout_after_err_in_run = timeout_after_err_in_run
44
+
45
+ def sync_run_startup_funcs(self):
46
+ for startup_func in self.startup_funcs:
47
+ if is_async_function(startup_func):
48
+ asyncio.run(startup_func())
49
+ elif is_sync_function(startup_func):
50
+ startup_func()
51
+ else:
52
+ raise TypeError("no sync and not async")
22
53
 
23
54
  def sync_on_startup(self):
24
- pass
55
+ self.sync_run_startup_funcs()
25
56
 
26
57
  def sync_run(self):
27
- self._logger.info("hello world")
58
+ self._logger.info(f"hello world, im {self.worker_fullname}")
28
59
 
29
- def sync_run_on_error(self, exception: BaseException, **kwargs):
60
+ def sync_on_error(self, exception: BaseException, **kwargs):
30
61
  pass
31
62
 
32
63
  def sync_safe_run(self):
@@ -42,20 +73,29 @@ class BaseWorker(ABC):
42
73
  except BaseException as exception:
43
74
  self._logger.error("error in sync_run", exc_info=exception)
44
75
  try:
45
- self.sync_run_on_error(exception=exception)
76
+ self.sync_on_error(exception=exception)
46
77
  except BaseException as exception_:
47
- self._logger.error("error in sync_run_on_error", exc_info=exception_)
78
+ self._logger.error("error in sync_on_error", exc_info=exception_)
48
79
  raise exception_
49
- if self.timeout_after_run is not None:
50
- sync_safe_sleep(self.timeout_after_run)
80
+ sync_safe_sleep(self.timeout_after_err_in_run)
81
+ sync_safe_sleep(self.timeout_after_run)
82
+
83
+ async def async_run_startup_funcs(self):
84
+ for startup_func in self.startup_funcs:
85
+ if is_async_function(startup_func):
86
+ await startup_func()
87
+ elif is_sync_function(startup_func):
88
+ startup_func()
89
+ else:
90
+ raise TypeError("no sync and not async")
51
91
 
52
92
  async def async_on_startup(self):
53
- pass
93
+ await self.async_run_startup_funcs()
54
94
 
55
95
  async def async_run(self):
56
- self._logger.info("hello world")
96
+ self._logger.info(f"hello world, im {self.worker_fullname}")
57
97
 
58
- async def async_run_on_error(self, exception: BaseException, **kwargs):
98
+ async def async_on_error(self, exception: BaseException, **kwargs):
59
99
  pass
60
100
 
61
101
  async def async_safe_run(self):
@@ -71,12 +111,12 @@ class BaseWorker(ABC):
71
111
  except BaseException as exception:
72
112
  self._logger.error("error in async_run", exc_info=exception)
73
113
  try:
74
- await self.async_run_on_error(exception=exception)
114
+ await self.async_on_error(exception=exception)
75
115
  except BaseException as exception_:
76
- self._logger.error("error in async_run_on_error", exc_info=exception_)
116
+ self._logger.error("error in async_on_error", exc_info=exception_)
77
117
  raise exception_
78
- if self.timeout_after_err_in_run is not None:
79
118
  await async_safe_sleep(self.timeout_after_err_in_run)
119
+ await async_safe_sleep(self.timeout_after_run)
80
120
 
81
121
 
82
122
  class SafeRunInBackgroundModes(Enumeration):
@@ -107,6 +147,15 @@ def safe_run_worker_in_background(*, worker: BaseWorker, mode: str) -> (
107
147
  return res
108
148
 
109
149
 
150
+ def safe_run_workers_in_background(
151
+ *, workers: list[BaseWorker], mode: str
152
+ ) -> list[asyncio.Task] | list[threading.Thread] | list[multiprocessing.Process]:
153
+ res = []
154
+ for worker in workers:
155
+ res.append(safe_run_worker_in_background(worker=worker, mode=mode))
156
+ return res
157
+
158
+
110
159
  def __example():
111
160
  pass
112
161
 
@@ -1,5 +1,18 @@
1
1
  import traceback
2
2
 
3
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
+
3
5
 
4
6
  def exception_to_traceback_str(exception: BaseException) -> str:
5
7
  return "".join(traceback.format_exception(type(exception), exception, exception.__traceback__))
8
+
9
+
10
+ def __example():
11
+ try:
12
+ raise Exception()
13
+ except Exception as exception:
14
+ print(exception_to_traceback_str(exception))
15
+
16
+
17
+ if __name__ == '__main__':
18
+ __example()