arpakitlib 1.4.0__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.

Potentially problematic release.


This version of arpakitlib might be problematic. Click here for more details.

Files changed (68) hide show
  1. arpakitlib/AUTHOR.md +6 -0
  2. arpakitlib/LICENSE +201 -0
  3. arpakitlib/NOTICE +2 -0
  4. arpakitlib/README.md +6 -0
  5. arpakitlib/__init__.py +0 -0
  6. arpakitlib/ar_additional_model_util.py +8 -0
  7. arpakitlib/ar_aiogram_util.py +363 -0
  8. arpakitlib/ar_arpakit_lib_module_util.py +150 -0
  9. arpakitlib/ar_arpakit_schedule_uust_api_client.py +527 -0
  10. arpakitlib/ar_arpakitlib_info.py +11 -0
  11. arpakitlib/ar_base64_util.py +30 -0
  12. arpakitlib/ar_base_worker.py +77 -0
  13. arpakitlib/ar_cache_file.py +124 -0
  14. arpakitlib/ar_datetime_util.py +38 -0
  15. arpakitlib/ar_dict_util.py +24 -0
  16. arpakitlib/ar_dream_ai_api_client.py +120 -0
  17. arpakitlib/ar_encrypt_and_decrypt_util.py +23 -0
  18. arpakitlib/ar_enumeration.py +76 -0
  19. arpakitlib/ar_fastapi_static/redoc/redoc.standalone.js +1826 -0
  20. arpakitlib/ar_fastapi_static/swagger-ui/favicon-16x16.png +0 -0
  21. arpakitlib/ar_fastapi_static/swagger-ui/favicon-32x32.png +0 -0
  22. arpakitlib/ar_fastapi_static/swagger-ui/index.css +16 -0
  23. arpakitlib/ar_fastapi_static/swagger-ui/index.html +19 -0
  24. arpakitlib/ar_fastapi_static/swagger-ui/oauth2-redirect.html +79 -0
  25. arpakitlib/ar_fastapi_static/swagger-ui/swagger-initializer.js +20 -0
  26. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-bundle.js +2 -0
  27. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-bundle.js.map +1 -0
  28. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-es-bundle-core.js +3 -0
  29. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-es-bundle-core.js.map +1 -0
  30. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-es-bundle.js +2 -0
  31. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-es-bundle.js.map +1 -0
  32. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-standalone-preset.js +2 -0
  33. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-standalone-preset.js.map +1 -0
  34. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui.css +3 -0
  35. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui.css.map +1 -0
  36. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui.js +2 -0
  37. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui.js.map +1 -0
  38. arpakitlib/ar_fastapi_util.py +294 -0
  39. arpakitlib/ar_file_storage_in_dir.py +127 -0
  40. arpakitlib/ar_generate_env_example.py +16 -0
  41. arpakitlib/ar_hash_util.py +19 -0
  42. arpakitlib/ar_http_request_util.py +75 -0
  43. arpakitlib/ar_ip_util.py +50 -0
  44. arpakitlib/ar_json_db.py +231 -0
  45. arpakitlib/ar_json_util.py +28 -0
  46. arpakitlib/ar_jwt_util.py +38 -0
  47. arpakitlib/ar_list_of_dicts_to_xlsx.py +32 -0
  48. arpakitlib/ar_list_util.py +26 -0
  49. arpakitlib/ar_logging_util.py +45 -0
  50. arpakitlib/ar_mongodb_util.py +143 -0
  51. arpakitlib/ar_need_type_util.py +58 -0
  52. arpakitlib/ar_openai_util.py +59 -0
  53. arpakitlib/ar_parse_command.py +102 -0
  54. arpakitlib/ar_postgresql_util.py +45 -0
  55. arpakitlib/ar_run_cmd.py +48 -0
  56. arpakitlib/ar_safe_sleep.py +23 -0
  57. arpakitlib/ar_schedule_uust_api_client.py +216 -0
  58. arpakitlib/ar_sqlalchemy_util.py +124 -0
  59. arpakitlib/ar_ssh_runner.py +260 -0
  60. arpakitlib/ar_str_util.py +79 -0
  61. arpakitlib/ar_type_util.py +82 -0
  62. arpakitlib/ar_yookassa_api_client.py +224 -0
  63. arpakitlib/ar_zabbix_util.py +190 -0
  64. arpakitlib-1.4.0.dist-info/LICENSE +201 -0
  65. arpakitlib-1.4.0.dist-info/METADATA +327 -0
  66. arpakitlib-1.4.0.dist-info/NOTICE +2 -0
  67. arpakitlib-1.4.0.dist-info/RECORD +68 -0
  68. arpakitlib-1.4.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,260 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ from datetime import timedelta
6
+ from typing import Optional, Any
7
+
8
+ import asyncssh
9
+ import paramiko
10
+ from pydantic import BaseModel
11
+
12
+ from arpakitlib.ar_json_util import safely_transfer_to_json_str
13
+
14
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
15
+
16
+
17
+ class SSHRunTimeouts:
18
+ fast_command = timedelta(minutes=0, seconds=15).total_seconds()
19
+ medium_command = timedelta(minutes=2, seconds=30).total_seconds()
20
+ long_command = timedelta(minutes=5, seconds=0).total_seconds()
21
+
22
+
23
+ class SSHBaseErr(Exception):
24
+ pass
25
+
26
+
27
+ class SSHCannotConnect(SSHBaseErr):
28
+ pass
29
+
30
+
31
+ class SSHCannotRun(SSHBaseErr):
32
+ pass
33
+
34
+
35
+ class SSHRunResHasErr(SSHBaseErr):
36
+
37
+ def __init__(self, ssh_run_res: SSHRunRes):
38
+ self.ssh_run_res = ssh_run_res
39
+
40
+ def __repr__(self):
41
+ return f"return_code={self.ssh_run_res.return_code}, stderr={self.ssh_run_res.err.strip()}"
42
+
43
+ def __str__(self):
44
+ return f"return_code={self.ssh_run_res.return_code}, stderr={self.ssh_run_res.err.strip()}"
45
+
46
+
47
+ class SSHRunRes(BaseModel):
48
+ out: str
49
+ err: str
50
+ return_code: int | None = None
51
+
52
+ def simple_dict(self) -> dict[str, Any]:
53
+ return {
54
+ "out": self.out,
55
+ "err": self.err,
56
+ "return_code": self.return_code,
57
+ "has_bad_return_code": self.has_bad_return_code,
58
+ "has_err": self.has_err
59
+ }
60
+
61
+ def simple_json(self) -> str:
62
+ return safely_transfer_to_json_str(self.simple_dict())
63
+
64
+ def __repr__(self) -> str:
65
+ return self.simple_json()
66
+
67
+ def __str__(self) -> str:
68
+ return self.simple_json()
69
+
70
+ @property
71
+ def has_bad_return_code(self) -> bool:
72
+ if self.return_code is None:
73
+ return False
74
+ return self.return_code != 0
75
+
76
+ @property
77
+ def has_err(self) -> bool:
78
+ if self.err:
79
+ return True
80
+ return False
81
+
82
+ def raise_for_bad_return_code(self):
83
+ if self.has_bad_return_code:
84
+ raise SSHRunResHasErr(ssh_run_res=self)
85
+
86
+ def raise_for_err(self):
87
+ if self.has_err:
88
+ raise SSHRunResHasErr(ssh_run_res=self)
89
+
90
+
91
+ class SSHRunner:
92
+
93
+ def __init__(
94
+ self,
95
+ *,
96
+ hostname: str,
97
+ port: int = 22,
98
+ username: str = "root",
99
+ password: Optional[str] = None,
100
+ base_timeout: int = timedelta(seconds=5).total_seconds()
101
+ ):
102
+ self.hostname = hostname
103
+ self.port = port
104
+ self.username = username
105
+ self.password = password
106
+
107
+ self.base_timeout = base_timeout
108
+
109
+ self._logger = logging.getLogger(
110
+ f"{logging.getLogger(self.__class__.__name__)} - {self.username}@{self.hostname}:{self.port}"
111
+ )
112
+
113
+ self.async_conn: Optional[asyncssh.SSHClientConnection] = None
114
+
115
+ self.sync_client = paramiko.SSHClient()
116
+ self.sync_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
117
+
118
+ """SYNC"""
119
+
120
+ def sync_connect(self) -> SSHRunner:
121
+ try:
122
+ self.sync_client.connect(
123
+ hostname=self.hostname,
124
+ username=self.username,
125
+ password=self.password,
126
+ port=self.port,
127
+ timeout=self.base_timeout,
128
+ auth_timeout=self.base_timeout,
129
+ banner_timeout=self.base_timeout,
130
+ channel_timeout=self.base_timeout
131
+ )
132
+ except Exception as err:
133
+ raise SSHCannotConnect(err)
134
+ return self
135
+
136
+ def sync_check_connection(self):
137
+ self.sync_connect()
138
+
139
+ def sync_is_conn_good(self) -> bool:
140
+ try:
141
+ self.sync_check_connection()
142
+ except SSHCannotConnect:
143
+ return False
144
+ return True
145
+
146
+ def sync_run(
147
+ self,
148
+ command: str,
149
+ *,
150
+ timeout: float | None = SSHRunTimeouts.medium_command,
151
+ raise_for_bad_return_code: bool = True
152
+ ) -> SSHRunRes:
153
+ if timeout is None:
154
+ timeout = self.base_timeout
155
+
156
+ self._logger.info(command)
157
+
158
+ self.sync_connect()
159
+
160
+ try:
161
+ stdin, stdout, stderr = self.sync_client.exec_command(
162
+ command=command,
163
+ timeout=timeout
164
+ )
165
+ return_code = stdout.channel.recv_exit_status()
166
+ stdout = stdout.read().decode()
167
+ stderr = stderr.read().decode()
168
+ except Exception as err:
169
+ raise SSHCannotRun(err)
170
+
171
+ ssh_run_res = SSHRunRes(
172
+ out=stdout,
173
+ err=stderr,
174
+ return_code=return_code
175
+ )
176
+ if raise_for_bad_return_code is True:
177
+ ssh_run_res.raise_for_bad_return_code()
178
+
179
+ return ssh_run_res
180
+
181
+ def sync_close(self):
182
+ self.sync_client.close()
183
+
184
+ """ASYNC SYNC"""
185
+
186
+ async def async_connect(self) -> SSHRunner:
187
+ if self.async_conn is None:
188
+ try:
189
+ self.async_conn = await asyncssh.connect(
190
+ host=self.hostname,
191
+ username=self.username,
192
+ password=self.password,
193
+ port=self.port,
194
+ connect_timeout=self.base_timeout,
195
+ known_hosts=None
196
+ )
197
+ except Exception as err:
198
+ raise SSHCannotConnect(err)
199
+ return self
200
+
201
+ async def async_check_connection(self):
202
+ await self.async_connect()
203
+
204
+ async def async_is_conn_good(self) -> bool:
205
+ try:
206
+ await self.async_check_connection()
207
+ except SSHCannotConnect:
208
+ return False
209
+ return True
210
+
211
+ async def async_run(
212
+ self,
213
+ command: str,
214
+ *,
215
+ timeout: float | None = SSHRunTimeouts.medium_command,
216
+ raise_for_bad_return_code: bool = True
217
+ ) -> SSHRunRes:
218
+ if timeout is None:
219
+ timeout = self.base_timeout
220
+
221
+ self._logger.info(command)
222
+
223
+ await self.async_connect()
224
+
225
+ try:
226
+ result: asyncssh.SSHCompletedProcess = await self.async_conn.run(
227
+ command,
228
+ check=False,
229
+ timeout=timeout
230
+ )
231
+ except Exception as err:
232
+ raise SSHCannotRun(err)
233
+
234
+ ssh_run_res = SSHRunRes(
235
+ out=result.stdout,
236
+ err=result.stderr,
237
+ return_code=result.returncode
238
+ )
239
+ if raise_for_bad_return_code is True:
240
+ ssh_run_res.raise_for_bad_return_code()
241
+
242
+ return ssh_run_res
243
+
244
+ def async_close(self):
245
+ if self.async_conn is not None:
246
+ self.async_conn.close()
247
+ self.async_conn = None
248
+
249
+
250
+ def __example():
251
+ pass
252
+
253
+
254
+ async def __async_example():
255
+ pass
256
+
257
+
258
+ if __name__ == '__main__':
259
+ __example()
260
+ asyncio.run(__async_example())
@@ -0,0 +1,79 @@
1
+ from typing import Optional
2
+
3
+ from bs4 import BeautifulSoup
4
+
5
+ from arpakitlib.ar_type_util import raise_for_type
6
+
7
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
8
+
9
+
10
+ def str_in(string: str, main_string: str, *, max_diff: Optional[int] = None) -> bool:
11
+ if string not in main_string:
12
+ return False
13
+
14
+ if max_diff is None:
15
+ return True
16
+
17
+ diff = len(main_string) - len(string)
18
+ if diff <= max_diff:
19
+ return True
20
+
21
+ return False
22
+
23
+
24
+ def bidirectional_str_in(string1: str, string2: str, *, max_diff: Optional[int] = None) -> bool:
25
+ if (
26
+ str_in(string=string1, main_string=string2, max_diff=max_diff)
27
+ or str_in(string=string2, main_string=string1, max_diff=max_diff)
28
+ ):
29
+ return True
30
+ return False
31
+
32
+
33
+ def str_startswith(string: str, main_string: str, max_diff: Optional[int] = None) -> bool:
34
+ if not main_string.startswith(string):
35
+ return False
36
+
37
+ if max_diff is None:
38
+ return True
39
+
40
+ diff = len(main_string) - len(string)
41
+ if diff <= max_diff:
42
+ return True
43
+
44
+ return False
45
+
46
+
47
+ def bidirectional_str_startswith(string1: str, string2: str, max_diff: Optional[int] = None) -> bool:
48
+ if str_startswith(string1, string2, max_diff=max_diff) or str_startswith(string2, string1, max_diff=max_diff):
49
+ return True
50
+ return False
51
+
52
+
53
+ def blank_if_none(string: Optional[str] = None) -> str:
54
+ if string is None:
55
+ return ""
56
+ return string
57
+
58
+
59
+ def remove_html(string: str) -> str:
60
+ raise_for_type(string, str)
61
+ return BeautifulSoup(string, "html.parser").text
62
+
63
+
64
+ def remove_tags(string: str) -> str:
65
+ raise_for_type(string, str)
66
+ return string.replace("<", "").replace(">", "")
67
+
68
+
69
+ def remove_tags_and_html(string: str) -> str:
70
+ raise_for_type(string, str)
71
+ return remove_tags(remove_html(string))
72
+
73
+
74
+ def __example():
75
+ pass
76
+
77
+
78
+ if __name__ == '__main__':
79
+ __example()
@@ -0,0 +1,82 @@
1
+ from typing import Optional, Any
2
+
3
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
4
+
5
+
6
+ # ---
7
+
8
+
9
+ class NotSet:
10
+ pass
11
+
12
+
13
+ def is_set(v: Any) -> bool:
14
+ return not (v is NotSet or isinstance(v, NotSet))
15
+
16
+
17
+ def is_set_and_not_none(v: Any) -> bool:
18
+ return is_set(v) and (v is not None)
19
+
20
+
21
+ def is_not_set(v: Any) -> bool:
22
+ return not is_set(v)
23
+
24
+
25
+ def is_not_set_or_none(v: Any) -> bool:
26
+ return is_not_set(v) or (v is None)
27
+
28
+
29
+ def raise_if_set(v: Any):
30
+ if is_set(v):
31
+ raise ValueError("value is set")
32
+
33
+
34
+ def raise_if_not_set(v: Any):
35
+ if not is_set(v):
36
+ raise ValueError("value not set")
37
+
38
+
39
+ def make_none_if_not_set(v: Any) -> Any:
40
+ if is_not_set(v):
41
+ return None
42
+ return v
43
+
44
+
45
+ # ---
46
+
47
+
48
+ def raise_for_type(comparable, need_type, comment_for_error: Optional[str] = None):
49
+ if comparable is need_type:
50
+ return
51
+
52
+ if not isinstance(comparable, need_type):
53
+ err = f"raise_for_type, {comparable} != {need_type}, type {type(comparable)} != type {need_type}"
54
+ if comment_for_error:
55
+ err += f"\n{comment_for_error}"
56
+ raise TypeError(err)
57
+
58
+
59
+ def raise_for_types(comparable, need_types, comment_for_error: Optional[str] = None):
60
+ exceptions = []
61
+ for need_type in need_types:
62
+ try:
63
+ raise_for_type(comparable=comparable, need_type=need_type, comment_for_error=comment_for_error)
64
+ return
65
+ except TypeError as e:
66
+ exceptions.append(e)
67
+ if exceptions:
68
+ err = f"raise_for_types, {comparable} not in {need_types}, type {type(comparable)} not in {need_types}"
69
+ if comment_for_error:
70
+ err += f"\n{comment_for_error}"
71
+ raise TypeError(err)
72
+
73
+
74
+ # ---
75
+
76
+
77
+ def __example():
78
+ pass
79
+
80
+
81
+ if __name__ == '__main__':
82
+ __example()
@@ -0,0 +1,224 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ import uuid
6
+ from datetime import timedelta
7
+ from typing import Optional, Any
8
+
9
+ import aiohttp
10
+ import requests
11
+
12
+ from arpakitlib.ar_dict_util import combine_dicts
13
+ from arpakitlib.ar_enumeration import EasyEnumeration
14
+ from arpakitlib.ar_safe_sleep import safe_sleep
15
+ from arpakitlib.ar_type_util import raise_for_type
16
+
17
+ _ARPAKIT_LIB_MODULE_VERSION = "3.0"
18
+
19
+ """
20
+ https://yookassa.ru/developers/api
21
+ """
22
+
23
+
24
+ class YookassaPaymentStatuses(EasyEnumeration):
25
+ pending = "pending"
26
+ waiting_for_capture = "waiting_for_capture"
27
+ succeeded = "succeeded"
28
+ canceled = "canceled"
29
+
30
+
31
+ class YookassaAPIException(Exception):
32
+ pass
33
+
34
+
35
+ class YookassaAPIClient:
36
+ def __init__(self, *, secret_key: str, shop_id: int):
37
+ super().__init__()
38
+ self.secret_key = secret_key
39
+ self.shop_id = shop_id
40
+ self.headers = {"Content-Type": "application/json"}
41
+ self._logger = logging.getLogger(self.__class__.__name__)
42
+
43
+ def _sync_make_request(self, method: str, url: str, **kwargs) -> requests.Response:
44
+ max_tries = 7
45
+ tries = 0
46
+
47
+ kwargs["url"] = url
48
+ kwargs["method"] = method
49
+ kwargs["timeout"] = (timedelta(seconds=3).total_seconds(), timedelta(seconds=3).total_seconds())
50
+ if "headers" not in kwargs:
51
+ kwargs["headers"] = {}
52
+ kwargs["headers"] = combine_dicts(self.headers, kwargs["headers"])
53
+ kwargs["auth"] = (self.shop_id, self.secret_key)
54
+
55
+ while True:
56
+ self._logger.info(f"{method} {url}")
57
+ tries += 1
58
+ try:
59
+ return requests.request(**kwargs)
60
+ except Exception as err:
61
+ self._logger.warning(f"{tries}/{max_tries} {err} {method} {url}")
62
+ if tries >= max_tries:
63
+ raise YookassaAPIException(err)
64
+ safe_sleep(timedelta(seconds=0.1).total_seconds())
65
+ continue
66
+
67
+ async def _async_make_request(self, method: str, url: str, **kwargs) -> aiohttp.ClientResponse:
68
+ max_tries = 7
69
+ tries = 0
70
+
71
+ kwargs["url"] = url
72
+ kwargs["method"] = method
73
+ kwargs["timeout"] = aiohttp.ClientTimeout(total=timedelta(seconds=15).total_seconds())
74
+ if "headers" not in kwargs:
75
+ kwargs["headers"] = {}
76
+ kwargs["headers"] = combine_dicts(self.headers, kwargs["headers"])
77
+ kwargs["auth"] = aiohttp.BasicAuth(login=str(self.shop_id), password=self.secret_key)
78
+
79
+ while True:
80
+ self._logger.info(f"{method} {url}")
81
+ tries += 1
82
+ try:
83
+ async with aiohttp.ClientSession() as session:
84
+ async with session.request(**kwargs) as response:
85
+ await response.read()
86
+ return response
87
+ except Exception as err:
88
+ self._logger.warning(f"{tries}/{max_tries} {err} {method} {url}")
89
+ if tries >= max_tries:
90
+ raise YookassaAPIException(err)
91
+ await asyncio.sleep(timedelta(seconds=0.1).total_seconds())
92
+ continue
93
+
94
+ def sync_create_payment(
95
+ self,
96
+ json_body: dict[str, Any],
97
+ idempotence_key: Optional[str] = None
98
+ ) -> dict[str, Any]:
99
+
100
+ """
101
+ json_body example
102
+ json_body = {
103
+ "amount": {
104
+ "value": "2.0",
105
+ "currency": "RUB"
106
+ },
107
+ "description": "description",
108
+ "confirmation": {
109
+ "type": "redirect",
110
+ "return_url": f"https://t.me/{get_tg_bot_username()}",
111
+ "locale": "ru_RU"
112
+ },
113
+ "capture": True,
114
+ "metadata": {},
115
+ "merchant_customer_id": ""
116
+ }
117
+ """
118
+
119
+ if idempotence_key is None:
120
+ idempotence_key = str(uuid.uuid4())
121
+
122
+ headers = combine_dicts({"Idempotence-Key": idempotence_key})
123
+
124
+ response = self._sync_make_request(
125
+ method="POST",
126
+ url="https://api.yookassa.ru/v3/payments",
127
+ headers=headers,
128
+ json=json_body,
129
+ )
130
+
131
+ json_data = response.json()
132
+
133
+ response.raise_for_status()
134
+
135
+ return json_data
136
+
137
+ def sync_get_payment(self, payment_id: str) -> Optional[dict[str, Any]]:
138
+ raise_for_type(payment_id, str)
139
+
140
+ response = self._sync_make_request(
141
+ method="GET",
142
+ url=f"https://api.yookassa.ru/v3/payments/{payment_id}",
143
+ headers=self.headers
144
+ )
145
+
146
+ json_data = response.json()
147
+
148
+ if response.status_code == 404:
149
+ return None
150
+
151
+ response.raise_for_status()
152
+
153
+ return json_data
154
+
155
+ async def async_create_payment(
156
+ self, json_body: dict[str, Any], idempotence_key: Optional[str] = None
157
+ ) -> dict[str, Any]:
158
+
159
+ """
160
+ json_body example
161
+ json_body = {
162
+ "amount": {
163
+ "value": "2.0",
164
+ "currency": "RUB"
165
+ },
166
+ "description": "description",
167
+ "confirmation": {
168
+ "type": "redirect",
169
+ "return_url": f"https://t.me/{get_tg_bot_username()}",
170
+ "locale": "ru_RU"
171
+ },
172
+ "capture": True,
173
+ "metadata": {},
174
+ "merchant_customer_id": ""
175
+ }
176
+ """
177
+
178
+ if idempotence_key is None:
179
+ idempotence_key = str(uuid.uuid4())
180
+
181
+ headers = combine_dicts({"Idempotence-Key": idempotence_key})
182
+
183
+ response = await self._async_make_request(
184
+ method="POST",
185
+ url="https://api.yookassa.ru/v3/payments",
186
+ headers=headers,
187
+ json=json_body,
188
+ )
189
+
190
+ json_data = await response.json()
191
+
192
+ response.raise_for_status()
193
+
194
+ return json_data
195
+
196
+ async def async_get_payment(self, payment_id: str) -> Optional[dict[str, Any]]:
197
+ raise_for_type(payment_id, str)
198
+
199
+ response = await self._async_make_request(
200
+ method="GET",
201
+ url=f"https://api.yookassa.ru/v3/payments/{payment_id}",
202
+ )
203
+
204
+ json_data = await response.json()
205
+
206
+ if response.status == 404:
207
+ return None
208
+
209
+ response.raise_for_status()
210
+
211
+ return json_data
212
+
213
+
214
+ def __example():
215
+ pass
216
+
217
+
218
+ async def __async_example():
219
+ pass
220
+
221
+
222
+ if __name__ == '__main__':
223
+ __example()
224
+ asyncio.run(__async_example())