arpakitlib 1.8.273__py3-none-any.whl → 1.8.275__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.
- arpakitlib/ar_generate_celery_url.py +71 -0
- {arpakitlib-1.8.273.dist-info → arpakitlib-1.8.275.dist-info}/METADATA +1 -1
- {arpakitlib-1.8.273.dist-info → arpakitlib-1.8.275.dist-info}/RECORD +6 -6
- arpakitlib/ar_yookassa_api_client_util.py +0 -189
- {arpakitlib-1.8.273.dist-info → arpakitlib-1.8.275.dist-info}/WHEEL +0 -0
- {arpakitlib-1.8.273.dist-info → arpakitlib-1.8.275.dist-info}/entry_points.txt +0 -0
- {arpakitlib-1.8.273.dist-info → arpakitlib-1.8.275.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
from urllib.parse import quote_plus
|
2
|
+
|
3
|
+
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
4
|
+
|
5
|
+
|
6
|
+
def generate_celery_url(
|
7
|
+
*,
|
8
|
+
scheme: str = "redis", # или amqp, sqs, etc.
|
9
|
+
user: str | None = None,
|
10
|
+
password: str | None = None,
|
11
|
+
host: str = "127.0.0.1",
|
12
|
+
port: int | None = 6379,
|
13
|
+
database: str | int | None = 0, # для Redis — номер БД; для AMQP — vhost
|
14
|
+
**query_params
|
15
|
+
) -> str:
|
16
|
+
"""
|
17
|
+
Генерирует Celery broker/backend URL.
|
18
|
+
|
19
|
+
Примеры:
|
20
|
+
redis://:mypassword@redis:6379/0
|
21
|
+
amqp://user:pass@rabbit:5672/myvhost
|
22
|
+
redis://localhost:6379/1?ssl_cert_reqs=none
|
23
|
+
"""
|
24
|
+
# Формируем часть авторизации
|
25
|
+
auth_part = ""
|
26
|
+
if user and password:
|
27
|
+
auth_part = f"{quote_plus(user)}:{quote_plus(password)}@"
|
28
|
+
elif password and not user:
|
29
|
+
# Redis-style — пароль без юзера
|
30
|
+
auth_part = f":{quote_plus(password)}@"
|
31
|
+
elif user:
|
32
|
+
auth_part = f"{quote_plus(user)}@"
|
33
|
+
|
34
|
+
# Формируем хост и порт
|
35
|
+
host_part = host
|
36
|
+
if port:
|
37
|
+
host_part += f":{port}"
|
38
|
+
|
39
|
+
# Формируем "базу" (для Redis — номер, для AMQP — vhost)
|
40
|
+
db_part = ""
|
41
|
+
if database is not None:
|
42
|
+
db_part = f"/{quote_plus(str(database))}"
|
43
|
+
|
44
|
+
# Формируем query параметры
|
45
|
+
query_part = ""
|
46
|
+
if query_params:
|
47
|
+
query_items = [f"{key}={quote_plus(str(value))}" for key, value in query_params.items()]
|
48
|
+
query_part = f"?{'&'.join(query_items)}"
|
49
|
+
|
50
|
+
return f"{scheme}://{auth_part}{host_part}{db_part}{query_part}"
|
51
|
+
|
52
|
+
|
53
|
+
def __example():
|
54
|
+
print(generate_celery_url())
|
55
|
+
# → redis://127.0.0.1:6379/0
|
56
|
+
|
57
|
+
# Redis с паролем
|
58
|
+
print(generate_celery_url(password="supersecret", host="redis"))
|
59
|
+
# → redis://:supersecret@redis:6379/0
|
60
|
+
|
61
|
+
# RabbitMQ (AMQP)
|
62
|
+
print(generate_celery_url(scheme="amqp", user="guest", password="guest", host="rabbitmq"))
|
63
|
+
# → amqp://guest:guest@rabbitmq:6379/0
|
64
|
+
|
65
|
+
# Redis с параметрами
|
66
|
+
print(generate_celery_url(password="pass", ssl_cert_reqs="none", socket_timeout=10))
|
67
|
+
# → redis://:pass@127.0.0.1:6379/0?ssl_cert_reqs=none&socket_timeout=10
|
68
|
+
|
69
|
+
|
70
|
+
if __name__ == '__main__':
|
71
|
+
__example()
|
@@ -399,6 +399,7 @@ arpakitlib/ar_exception_util.py,sha256=3hZKsj34TZVdmd4JAQz7w515smWqB8o3gTwAEjuMd
|
|
399
399
|
arpakitlib/ar_file_storage_in_dir_util.py,sha256=Zh922S6-aIy0p_Fen8GTTrGpixpPQ6c-wFLukiSK4Ck,4091
|
400
400
|
arpakitlib/ar_file_util.py,sha256=GUdJYm1tUZnYpY-SIPRHAZBHGra8NKy1eYEI0D5AfhY,489
|
401
401
|
arpakitlib/ar_func_util.py,sha256=lG0bx_DtxWN4skbUim0liRZ6WUyLVV8Qfk6iZNtCZOs,1042
|
402
|
+
arpakitlib/ar_generate_celery_url.py,sha256=ddzOokXKZRGRDQu18amnW5ZaekcMihwsmyUn0FzpgVU,2274
|
402
403
|
arpakitlib/ar_generate_simple_code.py,sha256=EkrebrTi7sArSRAuxvN5BPm_A0-dFSCZgdoJhx5kPhk,344
|
403
404
|
arpakitlib/ar_hash_util.py,sha256=Iqy6KBAOLBQMFLWv676boI5sV7atT2B-fb7aCdHOmIQ,340
|
404
405
|
arpakitlib/ar_http_request_util.py,sha256=PCUtGOQIvNScrLqD_9Z8LqT-7a-lP2y-Y-CH5vGdn7Q,7663
|
@@ -430,9 +431,8 @@ arpakitlib/ar_sqlalchemy_drop_check_constraints.py,sha256=XEqnMrIwSYasW_UOJ8xU-J
|
|
430
431
|
arpakitlib/ar_sqlalchemy_util.py,sha256=nUDCxhu0l8P0eBCdLyXej3_yLvBlB3LrGhMWzAekm5E,16532
|
431
432
|
arpakitlib/ar_str_util.py,sha256=2lGpnXDf2h1cBZpVf5i1tX_HCv5iBd6IGnrCw4QWWlY,4350
|
432
433
|
arpakitlib/ar_type_util.py,sha256=Cs_tef-Fc5xeyAF54KgISCsP11NHyzIsglm4S3Xx7iM,4049
|
433
|
-
arpakitlib/
|
434
|
-
arpakitlib-1.8.
|
435
|
-
arpakitlib-1.8.
|
436
|
-
arpakitlib-1.8.
|
437
|
-
arpakitlib-1.8.
|
438
|
-
arpakitlib-1.8.273.dist-info/RECORD,,
|
434
|
+
arpakitlib-1.8.275.dist-info/METADATA,sha256=kVwmU3-XuutMHrTuEhuxs0Mw7Y29OF8nLX3m1ks8Xn0,3983
|
435
|
+
arpakitlib-1.8.275.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
436
|
+
arpakitlib-1.8.275.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
|
437
|
+
arpakitlib-1.8.275.dist-info/licenses/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
|
438
|
+
arpakitlib-1.8.275.dist-info/RECORD,,
|
@@ -1,189 +0,0 @@
|
|
1
|
-
# arpakit
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
import asyncio
|
6
|
-
import logging
|
7
|
-
import uuid
|
8
|
-
from datetime import timedelta
|
9
|
-
from typing import Optional, Any
|
10
|
-
|
11
|
-
import aiohttp
|
12
|
-
import requests
|
13
|
-
|
14
|
-
from arpakitlib.ar_dict_util import combine_dicts
|
15
|
-
from arpakitlib.ar_enumeration_util import Enumeration
|
16
|
-
from arpakitlib.ar_http_request_util import sync_make_http_request, async_make_http_request
|
17
|
-
from arpakitlib.ar_type_util import raise_for_type
|
18
|
-
|
19
|
-
_ARPAKIT_LIB_MODULE_VERSION = "3.0"
|
20
|
-
|
21
|
-
"""
|
22
|
-
https://yookassa.ru/developers/api
|
23
|
-
"""
|
24
|
-
|
25
|
-
|
26
|
-
class YookassaPaymentStatuses(Enumeration):
|
27
|
-
pending = "pending"
|
28
|
-
waiting_for_capture = "waiting_for_capture"
|
29
|
-
succeeded = "succeeded"
|
30
|
-
canceled = "canceled"
|
31
|
-
|
32
|
-
|
33
|
-
class YookassaAPIException(Exception):
|
34
|
-
pass
|
35
|
-
|
36
|
-
|
37
|
-
class YookassaAPIClient:
|
38
|
-
def __init__(self, *, secret_key: str, shop_id: int):
|
39
|
-
super().__init__()
|
40
|
-
self.secret_key = secret_key
|
41
|
-
self.shop_id = shop_id
|
42
|
-
self.headers = {"Content-Type": "application/json"}
|
43
|
-
self.timeout_ = timedelta(seconds=3)
|
44
|
-
self._logger = logging.getLogger(self.__class__.__name__)
|
45
|
-
|
46
|
-
def _sync_make_http_request(
|
47
|
-
self,
|
48
|
-
*,
|
49
|
-
method: str,
|
50
|
-
url: str,
|
51
|
-
headers: dict[str, Any] | None = None,
|
52
|
-
**kwargs
|
53
|
-
) -> requests.Response:
|
54
|
-
return sync_make_http_request(
|
55
|
-
method=method,
|
56
|
-
url=url,
|
57
|
-
headers=combine_dicts(self.headers, (headers if headers is not None else {})),
|
58
|
-
max_tries_=5,
|
59
|
-
raise_for_status_=True,
|
60
|
-
timeout_=self.timeout_,
|
61
|
-
not_raise_for_statuses_=[404],
|
62
|
-
auth=(self.shop_id, self.secret_key),
|
63
|
-
**kwargs
|
64
|
-
)
|
65
|
-
|
66
|
-
def sync_create_payment(
|
67
|
-
self,
|
68
|
-
json_body: dict[str, Any]
|
69
|
-
) -> dict[str, Any]:
|
70
|
-
|
71
|
-
"""
|
72
|
-
json_body example
|
73
|
-
json_body = {
|
74
|
-
"amount": {
|
75
|
-
"value": "2.0",
|
76
|
-
"currency": "RUB"
|
77
|
-
},
|
78
|
-
"description": "description",
|
79
|
-
"confirmation": {
|
80
|
-
"type": "redirect",
|
81
|
-
"return_url": f"https://t.me/{get_tg_bot_username()}",
|
82
|
-
"locale": "ru_RU"
|
83
|
-
},
|
84
|
-
"capture": True,
|
85
|
-
"metadata": {},
|
86
|
-
"merchant_customer_id": ""
|
87
|
-
}
|
88
|
-
"""
|
89
|
-
|
90
|
-
response = self._sync_make_http_request(
|
91
|
-
method="POST",
|
92
|
-
url="https://api.yookassa.ru/v3/payments",
|
93
|
-
headers={"Idempotence-Key": str(uuid.uuid4())},
|
94
|
-
json=json_body,
|
95
|
-
)
|
96
|
-
json_data = response.json()
|
97
|
-
response.raise_for_status()
|
98
|
-
return json_data
|
99
|
-
|
100
|
-
def sync_get_payment(self, payment_id: str) -> dict[str, Any] | None:
|
101
|
-
raise_for_type(payment_id, str)
|
102
|
-
response = self._sync_make_http_request(
|
103
|
-
method="GET",
|
104
|
-
url=f"https://api.yookassa.ru/v3/payments/{payment_id}",
|
105
|
-
headers=self.headers
|
106
|
-
)
|
107
|
-
json_data = response.json()
|
108
|
-
if response.status_code == 404:
|
109
|
-
return None
|
110
|
-
response.raise_for_status()
|
111
|
-
return json_data
|
112
|
-
|
113
|
-
async def _async_make_http_request(
|
114
|
-
self,
|
115
|
-
*,
|
116
|
-
method: str = "GET",
|
117
|
-
url: str,
|
118
|
-
headers: dict[str, Any] | None = None,
|
119
|
-
**kwargs
|
120
|
-
) -> aiohttp.ClientResponse:
|
121
|
-
return await async_make_http_request(
|
122
|
-
method=method,
|
123
|
-
url=url,
|
124
|
-
headers=combine_dicts(self.headers, (headers if headers is not None else {})),
|
125
|
-
max_tries_=5,
|
126
|
-
raise_for_status_=True,
|
127
|
-
not_raise_for_statuses_=[404],
|
128
|
-
timeout_=self.timeout_,
|
129
|
-
auth=aiohttp.BasicAuth(login=str(self.shop_id), password=self.secret_key),
|
130
|
-
**kwargs
|
131
|
-
)
|
132
|
-
|
133
|
-
async def async_create_payment(
|
134
|
-
self, json_body: dict[str, Any]
|
135
|
-
) -> dict[str, Any]:
|
136
|
-
|
137
|
-
"""
|
138
|
-
json_body example
|
139
|
-
json_body = {
|
140
|
-
"amount": {
|
141
|
-
"value": "2.0",
|
142
|
-
"currency": "RUB"
|
143
|
-
},
|
144
|
-
"description": "description",
|
145
|
-
"confirmation": {
|
146
|
-
"type": "redirect",
|
147
|
-
"return_url": f"https://t.me/{get_tg_bot_username()}",
|
148
|
-
"locale": "ru_RU"
|
149
|
-
},
|
150
|
-
"capture": True,
|
151
|
-
"metadata": {},
|
152
|
-
"merchant_customer_id": ""
|
153
|
-
}
|
154
|
-
"""
|
155
|
-
|
156
|
-
response = await self._async_make_http_request(
|
157
|
-
method="POST",
|
158
|
-
url="https://api.yookassa.ru/v3/payments",
|
159
|
-
headers={"Idempotence-Key": str(uuid.uuid4())},
|
160
|
-
json=json_body,
|
161
|
-
)
|
162
|
-
json_data = await response.json()
|
163
|
-
response.raise_for_status()
|
164
|
-
return json_data
|
165
|
-
|
166
|
-
async def async_get_payment(self, payment_id: str) -> Optional[dict[str, Any]]:
|
167
|
-
raise_for_type(payment_id, str)
|
168
|
-
response = await self._async_make_http_request(
|
169
|
-
method="GET",
|
170
|
-
url=f"https://api.yookassa.ru/v3/payments/{payment_id}",
|
171
|
-
)
|
172
|
-
json_data = await response.json()
|
173
|
-
if response.status == 404:
|
174
|
-
return None
|
175
|
-
response.raise_for_status()
|
176
|
-
return json_data
|
177
|
-
|
178
|
-
|
179
|
-
def __example():
|
180
|
-
pass
|
181
|
-
|
182
|
-
|
183
|
-
async def __async_example():
|
184
|
-
pass
|
185
|
-
|
186
|
-
|
187
|
-
if __name__ == '__main__':
|
188
|
-
__example()
|
189
|
-
asyncio.run(__async_example())
|
File without changes
|
File without changes
|
File without changes
|