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
@@ -21,18 +21,18 @@ from fastapi import FastAPI, APIRouter, Query, Security, Depends
21
21
  from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html
22
22
  from fastapi.security import APIKeyHeader
23
23
  from pydantic import BaseModel, ConfigDict
24
+ from starlette import status
24
25
  from starlette.middleware.cors import CORSMiddleware
25
26
  from starlette.staticfiles import StaticFiles
26
27
 
27
- from arpakitlib.ar_base_worker_util import BaseWorker
28
28
  from arpakitlib.ar_dict_util import combine_dicts
29
29
  from arpakitlib.ar_enumeration_util import Enumeration
30
- from arpakitlib.ar_file_storage_in_dir_util import FileStorageInDir
31
- from arpakitlib.ar_json_util import safely_transfer_to_json_str_to_json_obj
30
+ from arpakitlib.ar_func_util import raise_if_not_async_func, is_async_function, is_async_object
31
+ from arpakitlib.ar_json_util import safely_transfer_obj_to_json_str_to_json_obj
32
32
  from arpakitlib.ar_logging_util import setup_normal_logging
33
- from arpakitlib.ar_sqlalchemy_model_util import StoryLogDBM
33
+ from arpakitlib.ar_sqlalchemy_model_util import StoryLogDBM, OperationDBM
34
34
  from arpakitlib.ar_sqlalchemy_util import SQLAlchemyDB
35
- from arpakitlib.ar_type_util import raise_for_type, raise_if_not_async_func, raise_if_none
35
+ from arpakitlib.ar_type_util import raise_for_type, raise_if_none
36
36
 
37
37
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
38
38
 
@@ -96,6 +96,10 @@ class StoryLogSO(SimpleSO):
96
96
  title: str | None
97
97
  data: dict[str, Any]
98
98
 
99
+ @classmethod
100
+ def from_story_log_dbm(cls, *, story_log_dbm: StoryLogDBM) -> StoryLogSO:
101
+ return cls.model_validate(story_log_dbm.simple_dict(include_sd_properties=True))
102
+
99
103
 
100
104
  class OperationSO(SimpleSO):
101
105
  execution_start_dt: datetime | None
@@ -107,13 +111,29 @@ class OperationSO(SimpleSO):
107
111
  error_data: dict[str, Any]
108
112
  duration_total_seconds: float | None
109
113
 
114
+ @classmethod
115
+ def from_operation_dbm(cls, *, operation_dbm: OperationDBM) -> OperationSO:
116
+ return cls.model_validate(operation_dbm.simple_dict(include_sd_properties=True))
117
+
110
118
 
111
119
  class APIJSONResponse(fastapi.responses.JSONResponse):
112
- def __init__(self, *, content: BaseSO, status_code: int = starlette.status.HTTP_200_OK):
120
+ def __init__(self, *, content: dict | list | BaseSO | None, status_code: int = starlette.status.HTTP_200_OK):
121
+ if isinstance(content, dict):
122
+ content = safely_transfer_obj_to_json_str_to_json_obj(content)
123
+ elif isinstance(content, list):
124
+ content = safely_transfer_obj_to_json_str_to_json_obj(content)
125
+ elif isinstance(content, BaseSO):
126
+ content = safely_transfer_obj_to_json_str_to_json_obj(content.model_dump())
127
+ elif content is None:
128
+ content = None
129
+ else:
130
+ raise ValueError(f"unknown content type, type(content)={type(content)}")
131
+
113
132
  self.content_ = content
114
133
  self.status_code_ = status_code
134
+
115
135
  super().__init__(
116
- content=safely_transfer_to_json_str_to_json_obj(content.model_dump()),
136
+ content=content,
117
137
  status_code=status_code
118
138
  )
119
139
 
@@ -221,6 +241,12 @@ def create_handle_exception(
221
241
  error_so.error_specification_code.upper().replace(" ", "_").strip()
222
242
  )
223
243
 
244
+ if error_so.error_code == BaseAPIErrorCodes.not_found:
245
+ status_code = status.HTTP_404_NOT_FOUND
246
+
247
+ if error_so.error_code == BaseAPIErrorCodes.cannot_authorize:
248
+ status_code = status.HTTP_401_UNAUTHORIZED
249
+
224
250
  if _need_exc_info:
225
251
  _logger.error(str(exception), exc_info=exception)
226
252
  else:
@@ -231,7 +257,7 @@ def create_handle_exception(
231
257
  _func_data = func(
232
258
  status_code=status_code, error_so=error_so, request=request, exception=exception, **_kwargs
233
259
  )
234
- if asyncio.iscoroutine(_func_data):
260
+ if is_async_function(_func_data):
235
261
  _func_data = await _func_data
236
262
  if _func_data is not None:
237
263
  status_code, error_so, _kwargs = _func_data[0], _func_data[1], _func_data[2]
@@ -403,37 +429,6 @@ class BaseShutdownAPIEvent:
403
429
  self._logger.info("on_shutdown ends")
404
430
 
405
431
 
406
- class InitSqlalchemyDBStartupAPIEvent(BaseStartupAPIEvent):
407
- def __init__(self, sqlalchemy_db: SQLAlchemyDB):
408
- super().__init__()
409
- self.sqlalchemy_db = sqlalchemy_db
410
-
411
- async def async_on_startup(self, *args, **kwargs):
412
- self.sqlalchemy_db.init()
413
-
414
-
415
- class SafeRunWorkerStartupAPIEvent(BaseStartupAPIEvent):
416
- def __init__(self, workers: list[BaseWorker], safe_run_in_background_mode: str):
417
- super().__init__()
418
- self.workers = workers
419
- self.safe_run_in_background_mode = safe_run_in_background_mode
420
-
421
- async def async_on_startup(self, *args, **kwargs):
422
- for worker in self.workers:
423
- _ = worker.safe_run_in_background(safe_run_in_background_mode=self.safe_run_in_background_mode)
424
-
425
-
426
- class InitFileStoragesInDir(BaseStartupAPIEvent):
427
- def __init__(self, file_storages_in_dir: list[FileStorageInDir | None]):
428
- super().__init__()
429
- file_storages_in_dir = [v for v in file_storages_in_dir if v is not None]
430
- self.file_storages_in_dir = file_storages_in_dir
431
-
432
- async def async_on_startup(self, *args, **kwargs):
433
- for file_storage_in_dir in self.file_storages_in_dir:
434
- file_storage_in_dir.init()
435
-
436
-
437
432
  class BaseTransmittedAPIData(BaseModel):
438
433
  model_config = ConfigDict(extra="ignore", arbitrary_types_allowed=True, from_attributes=True)
439
434
 
@@ -448,27 +443,63 @@ class BaseAPIAuthData(BaseModel):
448
443
  require_api_key_string: bool = False
449
444
  require_token_string: bool = False
450
445
 
446
+ require_correct_api_key: bool = False
447
+ require_correct_token: bool = False
448
+
451
449
  token_string: str | None = None
452
450
  api_key_string: str | None = None
453
451
 
452
+ is_token_string_correct: bool | None = None
453
+ is_api_key_string_correct: bool | None = None
454
+
454
455
 
455
456
  def base_api_auth(
456
457
  *,
457
458
  require_api_key_string: bool = False,
458
- require_token_string: bool = False
459
+ require_token_string: bool = False,
460
+ validate_api_key_func: Callable | None = None,
461
+ validate_token_func: Callable | None = None,
462
+ correct_api_keys: str | list[str] | None = None,
463
+ correct_tokens: str | list[str] | None = None,
464
+ require_correct_api_key: bool = False,
465
+ require_correct_token: bool = False,
466
+ **kwargs
459
467
  ) -> Callable:
468
+ if isinstance(correct_api_keys, str):
469
+ correct_api_keys = [correct_api_keys]
470
+ if correct_api_keys is not None:
471
+ raise_for_type(correct_api_keys, list)
472
+ validate_api_key_func = lambda *args, **kwargs_: kwargs_["api_key_string"] in correct_api_keys
473
+
474
+ if isinstance(correct_tokens, str):
475
+ correct_tokens = [correct_tokens]
476
+ if correct_tokens is not None:
477
+ raise_for_type(correct_tokens, list)
478
+ validate_token_func = lambda *args, **kwargs_: kwargs_["token_string"] in correct_tokens
479
+
480
+ if require_correct_api_key:
481
+ raise_if_none(validate_api_key_func)
482
+ require_api_key_string = True
483
+
484
+ if require_correct_token:
485
+ raise_if_none(validate_token_func)
486
+ require_token_string = True
487
+
460
488
  async def func(
461
489
  *,
462
490
  ac: fastapi.security.HTTPAuthorizationCredentials | None = fastapi.Security(
463
491
  fastapi.security.HTTPBearer(auto_error=False)
464
492
  ),
465
493
  api_key_string: str | None = Security(APIKeyHeader(name="apikey", auto_error=False)),
466
- request: starlette.requests.Request
494
+ request: starlette.requests.Request,
495
+ transmitted_api_data: BaseTransmittedAPIData = Depends(get_transmitted_api_data)
467
496
  ) -> BaseAPIAuthData:
468
497
 
469
498
  api_auth_data = BaseAPIAuthData(
470
499
  require_api_key_string=require_api_key_string,
471
- require_token_string=require_token_string
500
+ require_token_string=require_token_string,
501
+ require_correct_api_key=require_correct_api_key,
502
+ require_correct_token=require_correct_token
472
503
  )
473
504
 
474
505
  # api_key
@@ -518,63 +549,75 @@ def base_api_auth(
518
549
  if not api_auth_data.token_string:
519
550
  api_auth_data.token_string = None
520
551
 
552
+ # api_key
553
+
521
554
  if require_api_key_string and not api_auth_data.api_key_string:
522
555
  raise APIException(
523
556
  status_code=starlette.status.HTTP_401_UNAUTHORIZED,
524
557
  error_code=BaseAPIErrorCodes.cannot_authorize,
525
- error_data=safely_transfer_to_json_str_to_json_obj(api_auth_data.model_dump())
558
+ error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump())
526
559
  )
527
560
 
561
+ # token
562
+
528
563
  if require_token_string and not api_auth_data.token_string:
529
564
  raise APIException(
530
565
  status_code=starlette.status.HTTP_401_UNAUTHORIZED,
531
566
  error_code=BaseAPIErrorCodes.cannot_authorize,
532
- error_data=safely_transfer_to_json_str_to_json_obj(api_auth_data.model_dump())
567
+ error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump())
533
568
  )
534
569
 
535
- return api_auth_data
570
+ # api_key
536
571
 
537
- return func
572
+ if validate_api_key_func is not None:
573
+ validate_api_key_func_data = validate_api_key_func(
574
+ api_key_string=api_auth_data.api_key_string,
575
+ token_string=api_auth_data.token_string,
576
+ base_api_auth_data=api_auth_data,
577
+ transmitted_api_data=transmitted_api_data,
578
+ request=request,
579
+ **kwargs
580
+ )
581
+ if is_async_object(validate_api_key_func_data):
582
+ validate_api_key_func_data = await validate_api_key_func_data
583
+ api_auth_data.is_api_key_string_correct = validate_api_key_func_data
538
584
 
585
+ # token
539
586
 
540
- class CheckAPIKeyAPIAuthData(BaseAPIAuthData):
541
- is_api_key_correct: bool | None = None
587
+ if validate_token_func is not None:
588
+ validate_token_func_data = validate_token_func(
589
+ api_key_string=api_auth_data.api_key_string,
590
+ token_string=api_auth_data.token_string,
591
+ base_api_auth_data=api_auth_data,
592
+ transmitted_api_data=transmitted_api_data,
593
+ request=request,
594
+ **kwargs
595
+ )
596
+ if is_async_object(validate_token_func_data):
597
+ validate_token_func_data_data = await validate_token_func_data
598
+ api_auth_data.is_token_string_correct = validate_token_func_data_data
542
599
 
600
+ # api_key
543
601
 
544
- def is_api_key_correct_api_auth(
545
- *,
546
- validate_api_key_func: Callable | None = None,
547
- correct_api_key: str | None = None
548
- ):
549
- if correct_api_key is not None:
550
- validate_api_key_func = lambda *args, **kwargs: kwargs["api_key_string"] == correct_api_key
551
- raise_if_none(validate_api_key_func)
602
+ if require_correct_api_key:
603
+ if not api_auth_data.is_api_key_string_correct:
604
+ raise APIException(
605
+ status_code=starlette.status.HTTP_401_UNAUTHORIZED,
606
+ error_code=BaseAPIErrorCodes.cannot_authorize,
607
+ error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump())
608
+ )
552
609
 
553
- async def func(
554
- *,
555
- base_api_auth_data: BaseAPIAuthData = Depends(base_api_auth(
556
- require_api_key_string=True,
557
- require_token_string=False
558
- )),
559
- transmitted_api_data: BaseTransmittedAPIData = Depends(get_transmitted_api_data),
560
- request: starlette.requests.Request
561
- ) -> CheckAPIKeyAPIAuthData:
562
- check_api_key_api_auth_data = CheckAPIKeyAPIAuthData.model_validate(base_api_auth_data)
563
- check_api_key_api_auth_data.is_api_key_correct = validate_api_key_func(
564
- api_key_string=base_api_auth_data.api_key_string,
565
- base_api_auth_data=base_api_auth_data,
566
- transmitted_api_data=transmitted_api_data,
567
- request=request
568
- )
610
+ # token
569
611
 
570
- if not check_api_key_api_auth_data.is_api_key_correct:
571
- raise APIException(
572
- status_code=starlette.status.HTTP_401_UNAUTHORIZED,
573
- error_code=BaseAPIErrorCodes.cannot_authorize,
574
- error_data=safely_transfer_to_json_str_to_json_obj(check_api_key_api_auth_data.model_dump())
575
- )
612
+ if require_correct_token:
613
+ if not api_auth_data.is_token_string_correct:
614
+ raise APIException(
615
+ status_code=starlette.status.HTTP_401_UNAUTHORIZED,
616
+ error_code=BaseAPIErrorCodes.cannot_authorize,
617
+ error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump())
618
+ )
576
619
 
577
- return check_api_key_api_auth_data
620
+ return api_auth_data
578
621
 
579
622
  return func
580
623
 
@@ -617,18 +660,12 @@ def simple_api_router_for_testing():
617
660
  return router
618
661
 
619
662
 
620
- DEFAULT_CONTACT = {
621
- "name": "ARPAKIT Company",
622
- "email": "support@arpakit.com"
623
- }
624
-
625
-
626
663
  def create_fastapi_app(
627
664
  *,
628
665
  title: str = "arpakitlib FastAPI",
629
666
  description: str | None = "arpakitlib FastAPI",
630
667
  log_filepath: str | None = "./story.log",
631
- handle_exception_: Callable | None = create_handle_exception(),
668
+ handle_exception_: Callable | None = None,
632
669
  startup_api_events: list[BaseStartupAPIEvent | None] | None = None,
633
670
  shutdown_api_events: list[BaseShutdownAPIEvent | None] | None = None,
634
671
  transmitted_api_data: BaseTransmittedAPIData = BaseTransmittedAPIData(),
@@ -641,8 +678,8 @@ def create_fastapi_app(
641
678
 
642
679
  setup_normal_logging(log_filepath=log_filepath)
643
680
 
644
- if contact is None:
645
- contact = DEFAULT_CONTACT
681
+ if handle_exception_ is None:
682
+ handle_exception_ = create_handle_exception()
646
683
 
647
684
  if not startup_api_events:
648
685
  startup_api_events = [BaseStartupAPIEvent()]
@@ -679,16 +716,10 @@ def create_fastapi_app(
679
716
 
680
717
  add_swagger_to_app(app=app)
681
718
 
682
- if handle_exception_:
683
- add_exception_handler_to_app(
684
- app=app,
685
- handle_exception=handle_exception_
686
- )
687
- else:
688
- add_exception_handler_to_app(
689
- app=app,
690
- handle_exception=create_handle_exception()
691
- )
719
+ add_exception_handler_to_app(
720
+ app=app,
721
+ handle_exception=handle_exception_
722
+ )
692
723
 
693
724
  add_needed_api_router_to_app(app=app)
694
725
 
@@ -1,5 +1,7 @@
1
1
  import os
2
2
 
3
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
+
3
5
 
4
6
  def raise_if_path_not_exists(path: str):
5
7
  if not os.path.exists(path):
@@ -0,0 +1,55 @@
1
+ import asyncio
2
+ import inspect
3
+ from typing import Callable
4
+
5
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
6
+
7
+
8
+ def is_async_function(func: Callable) -> bool:
9
+ return asyncio.iscoroutinefunction(func)
10
+
11
+
12
+ def is_async_object(obj: object) -> bool:
13
+ return asyncio.iscoroutine(obj)
14
+
15
+
16
+ def is_sync_function(func: Callable) -> bool:
17
+ return inspect.isfunction(func) and not is_async_function(func)
18
+
19
+
20
+ def raise_if_not_async_func(func: Callable):
21
+ if not is_async_function(func):
22
+ raise TypeError(f"The provided function '{func.__name__}' is not an async function")
23
+
24
+
25
+ def raise_if_not_sync_func(func: Callable):
26
+ if not is_sync_function(func):
27
+ raise TypeError(f"The provided function '{func.__name__}' is not a sync function")
28
+
29
+
30
+ def raise_if_async_func(func: Callable):
31
+ if is_async_function(func):
32
+ raise TypeError(f"The provided function '{func.__name__}' should not be async")
33
+
34
+
35
+ def raise_if_sync_func(func: Callable):
36
+ if is_sync_function(func):
37
+ raise TypeError(f"The provided function '{func.__name__}' should not be sync")
38
+
39
+
40
+ def __example():
41
+ def one():
42
+ pass
43
+
44
+ async def two():
45
+ pass
46
+
47
+ print(is_sync_function(one))
48
+ print(is_sync_function(two))
49
+
50
+ print(is_async_function(one))
51
+ print(is_async_function(two))
52
+
53
+
54
+ if __name__ == '__main__':
55
+ __example()
@@ -1,29 +1,31 @@
1
1
  # arpakit
2
2
 
3
3
  import json
4
- from typing import Union, Any
4
+ from typing import Any
5
5
 
6
6
  _ARPAKIT_LIB_MODULE_VERSION = "3.0"
7
7
 
8
8
 
9
- def safely_transfer_to_json_obj(data: str) -> Union[dict, list]:
9
+ def safely_transfer_str_to_json_obj(data: str) -> dict[Any, Any] | list[Any] | None:
10
10
  if not isinstance(data, str):
11
11
  raise ValueError("not isinstance(data, str)")
12
12
  return json.loads(data)
13
13
 
14
14
 
15
- def safely_transfer_to_json_str(data: Union[dict[str, Any], list[Any]]) -> str:
16
- if not isinstance(data, dict) and not isinstance(data, list):
17
- raise ValueError("not isinstance(data, dict) and not isinstance(data, list)")
15
+ def safely_transfer_obj_to_json_str(data: dict[Any, Any] | list[Any] | None) -> str:
16
+ if not isinstance(data, dict) and not isinstance(data, list) and data is not None:
17
+ raise ValueError("not isinstance(data, dict) and not isinstance(data, list) and data is not None")
18
18
  return json.dumps(data, ensure_ascii=False, indent=2, default=str)
19
19
 
20
20
 
21
- def safely_transfer_to_json_str_to_json_obj(data: Union[dict[str, Any], list[Any]]) -> Union[dict, list]:
22
- return safely_transfer_to_json_obj(safely_transfer_to_json_str(data))
21
+ def safely_transfer_obj_to_json_str_to_json_obj(
22
+ data: dict[Any, Any] | list[Any] | None
23
+ ) -> dict[Any, Any] | list[Any] | None:
24
+ return safely_transfer_str_to_json_obj(safely_transfer_obj_to_json_str(data))
23
25
 
24
26
 
25
- def safely_transfer_to_json_obj_to_json_str(data: str) -> str:
26
- return safely_transfer_to_json_str(safely_transfer_to_json_obj(data))
27
+ def safely_transfer_str_to_json_obj_to_json_str(data: str) -> str:
28
+ return safely_transfer_obj_to_json_str(safely_transfer_str_to_json_obj(data))
27
29
 
28
30
 
29
31
  def __example():
@@ -56,7 +56,14 @@ def parse_need_type(value: Any, need_type: str, allow_none: bool = False) -> Any
56
56
 
57
57
 
58
58
  def __example():
59
- pass
59
+ print(parse_need_type(value=123, need_type="int"))
60
+ print(parse_need_type(value="True", need_type="bool"))
61
+ print(parse_need_type(value=123.456, need_type="float"))
62
+ print(parse_need_type(value='[1, 2, 3]', need_type="list_of_int"))
63
+ print(parse_need_type(value='["a", "b", "c"]', need_type="list_of_str"))
64
+ print(parse_need_type(value='[1.1, 2.2, 3.3]', need_type="list_of_float"))
65
+ print(parse_need_type(value='{"key": "value"}', need_type="json"))
66
+ print(parse_need_type(value="hello world", need_type="str"))
60
67
 
61
68
 
62
69
  if __name__ == '__main__':
@@ -49,11 +49,25 @@ class OpenAIAPIClient:
49
49
 
50
50
 
51
51
  def __example():
52
- pass
52
+ open_ai = OpenAI(api_key="your-api-key")
53
+ client = OpenAIAPIClient(open_ai=open_ai)
54
+
55
+ print("Checking OpenAI API connection...")
56
+ if client.is_conn_good():
57
+ print("Connection to OpenAI API is good")
58
+ else:
59
+ print("Failed to connect to OpenAI API")
53
60
 
54
61
 
55
62
  async def __async_example():
56
- pass
63
+ async_open_ai = AsyncOpenAI(api_key="your-api-key")
64
+ client = OpenAIAPIClient(async_open_ai=async_open_ai)
65
+
66
+ print("Checking OpenAI API async connection...")
67
+ if await client.async_is_conn_good():
68
+ print("Async connection to OpenAI API is good")
69
+ else:
70
+ print("Failed to async connect to OpenAI API")
57
71
 
58
72
 
59
73
  if __name__ == '__main__':