telegram-api-client-python 1.0.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.
@@ -0,0 +1,323 @@
1
+ import json
2
+ import logging
3
+ from typing import Any, NoReturn, Optional
4
+
5
+ import aiohttp
6
+ from requests import Response, Session
7
+ from requests.adapters import HTTPAdapter, Retry
8
+
9
+ from .response import Response as GreenAPIResponse
10
+ from .tools import (
11
+ account,
12
+ groups,
13
+ journals,
14
+ marking,
15
+ queues,
16
+ receiving,
17
+ sending,
18
+ serviceMethods,
19
+ webhooks,
20
+ partner
21
+ )
22
+
23
+
24
+ class GreenApi:
25
+ host: str
26
+ media: str
27
+ idInstance: str
28
+ apiTokenInstance: str
29
+
30
+ def __init__(
31
+ self,
32
+ idInstance: str,
33
+ apiTokenInstance: str,
34
+ debug_mode: bool = False,
35
+ raise_errors: bool = False,
36
+ host: str = "https://4100.api.green-api.com",
37
+ media: str = "https://4100.api.green-api.com",
38
+ host_timeout: float = 180, # sec per retry
39
+ media_timeout: float = 10800, # sec per retry
40
+ ):
41
+ self.host = host
42
+ self.media = media
43
+ self.debug_mode = debug_mode
44
+ self.raise_errors = raise_errors
45
+
46
+ # Change default values in init() if required
47
+ self.host_timeout = host_timeout
48
+ self.media_timeout = media_timeout
49
+
50
+ self.idInstance = idInstance
51
+ self.apiTokenInstance = apiTokenInstance
52
+
53
+ self.session = Session()
54
+ self.__prepare_session()
55
+
56
+ self.account = account.Account(self)
57
+ self.groups = groups.Groups(self)
58
+ self.journals = journals.Journals(self)
59
+ self.marking = marking.Marking(self)
60
+ self.queues = queues.Queues(self)
61
+ self.receiving = receiving.Receiving(self)
62
+ self.sending = sending.Sending(self)
63
+ self.serviceMethods = serviceMethods.ServiceMethods(self)
64
+ self.webhooks = webhooks.Webhooks(self)
65
+
66
+ self.logger = logging.getLogger("telegram-api-client-python")
67
+ self.__prepare_logger()
68
+
69
+ def request(
70
+ self,
71
+ method: str,
72
+ url: str,
73
+ payload: Optional[dict] = None,
74
+ files: Optional[dict] = None
75
+ ) -> GreenAPIResponse:
76
+ url = url.replace("{{host}}", self.host)
77
+ url = url.replace("{{media}}", self.media)
78
+ url = url.replace("{{idInstance}}", self.idInstance)
79
+ url = url.replace("{{apiTokenInstance}}", self.apiTokenInstance)
80
+
81
+ headers = {
82
+ 'User-Agent': 'GREEN-API_SDK_PY/1.0'
83
+ }
84
+
85
+ try:
86
+ if not files:
87
+ response = self.session.request(
88
+ method=method, url=url, json=payload, timeout=self.host_timeout, headers=headers
89
+ )
90
+ else:
91
+ response = self.session.request(
92
+ method=method, url=url, data=payload, files=files, timeout=self.media_timeout, headers=headers
93
+ )
94
+ except Exception as error:
95
+ error_message = f"Request was failed with error: {error}."
96
+
97
+ if self.raise_errors:
98
+ raise GreenAPIError(error_message)
99
+ self.logger.log(logging.CRITICAL, error_message)
100
+
101
+ return GreenAPIResponse(None, error_message)
102
+
103
+ self.__handle_response(response)
104
+
105
+ return GreenAPIResponse(response.status_code, response.text)
106
+
107
+ async def requestAsync(
108
+ self,
109
+ method: str,
110
+ url: str,
111
+ payload: Optional[dict] = None,
112
+ files: Optional[dict] = None
113
+ ) -> GreenAPIResponse:
114
+ url = url.replace("{{host}}", self.host)
115
+ url = url.replace("{{media}}", self.media)
116
+ url = url.replace("{{idInstance}}", self.idInstance)
117
+ url = url.replace("{{apiTokenInstance}}", self.apiTokenInstance)
118
+
119
+ headers = {
120
+ 'User-Agent': 'GREEN-API_SDK_PY/1.0'
121
+ }
122
+
123
+ try:
124
+ timeout = aiohttp.ClientTimeout(total=self.host_timeout if not files else self.media_timeout)
125
+
126
+ async with aiohttp.ClientSession(timeout=timeout, headers=headers) as session:
127
+ if not files:
128
+ async with session.request(method=method, url=url, json=payload) as response:
129
+ text = await response.text()
130
+ status_code = response.status
131
+ else:
132
+ data = aiohttp.FormData()
133
+ for key, value in (payload or {}).items():
134
+ if isinstance(value, (dict, list)):
135
+ data.add_field(key, json.dumps(value), content_type='application/json')
136
+ else:
137
+ data.add_field(key, str(value))
138
+
139
+ for field_name, file_data in files.items():
140
+ filename, file_obj, content_type = file_data
141
+ data.add_field(field_name, file_obj, filename=filename, content_type=content_type)
142
+
143
+ async with session.request(method=method, url=url, data=data) as response:
144
+ text = await response.text()
145
+ status_code = response.status
146
+
147
+ except Exception as error:
148
+ error_message = f"Async request was failed with error: {error}."
149
+
150
+ if self.raise_errors:
151
+ raise GreenAPIError(error_message)
152
+ self.logger.log(logging.CRITICAL, error_message)
153
+
154
+ return GreenAPIResponse(None, error_message)
155
+
156
+ self.__handle_response_async(status_code, text)
157
+ return GreenAPIResponse(status_code, text)
158
+
159
+ def raw_request(self, **arguments: Any) -> GreenAPIResponse:
160
+ try:
161
+ response = self.session.request(**arguments)
162
+ except Exception as error:
163
+ error_message = f"Request was failed with error: {error}."
164
+
165
+ if self.raise_errors:
166
+ raise GreenAPIError(error_message)
167
+ self.logger.log(logging.CRITICAL, error_message)
168
+
169
+ return GreenAPIResponse(None, error_message)
170
+
171
+ self.__handle_response(response)
172
+
173
+ return GreenAPIResponse(response.status_code, response.text)
174
+
175
+ async def raw_request_async(self, **arguments: Any) -> GreenAPIResponse:
176
+ try:
177
+ timeout = aiohttp.ClientTimeout(total=arguments.pop('timeout', self.host_timeout))
178
+ headers = arguments.pop('headers', {})
179
+ headers['User-Agent'] = 'GREEN-API_SDK_PY/1.0'
180
+
181
+ async with aiohttp.ClientSession(timeout=timeout, headers=headers) as session:
182
+ async with session.request(**arguments) as response:
183
+ text = await response.text()
184
+ status_code = response.status
185
+
186
+ except Exception as error:
187
+ error_message = f"Async raw request was failed with error: {error}."
188
+
189
+ if self.raise_errors:
190
+ raise GreenAPIError(error_message)
191
+ self.logger.log(logging.CRITICAL, error_message)
192
+
193
+ return GreenAPIResponse(None, error_message)
194
+
195
+ self.__handle_response_async(status_code, text)
196
+ return GreenAPIResponse(status_code, text)
197
+
198
+ def __handle_response(self, response: Response) -> Optional[NoReturn]:
199
+ status_code = response.status_code
200
+ if status_code != 200 or self.debug_mode:
201
+ try:
202
+ data = json.dumps(
203
+ json.loads(response.text), ensure_ascii=False, indent=4
204
+ )
205
+ except json.JSONDecodeError:
206
+ data = response.text
207
+
208
+ if status_code != 200:
209
+ error_message = (
210
+ f"Request was failed with status code: {status_code}."
211
+ f" Data: {data}"
212
+ )
213
+
214
+ if self.raise_errors:
215
+ raise GreenAPIError(error_message)
216
+ self.logger.log(logging.ERROR, error_message)
217
+
218
+ return None
219
+
220
+ self.logger.log(
221
+ logging.DEBUG, f"Request was successful with data: {data}"
222
+ )
223
+
224
+ def __handle_response_async(self, status_code: int, text: str) -> Optional[NoReturn]:
225
+ if status_code != 200 or self.debug_mode:
226
+ try:
227
+ data = json.dumps(
228
+ json.loads(text), ensure_ascii=False, indent=4
229
+ )
230
+ except json.JSONDecodeError:
231
+ data = text
232
+
233
+ if status_code != 200:
234
+ error_message = (
235
+ f"Async request was failed with status code: {status_code}."
236
+ f" Data: {data}"
237
+ )
238
+
239
+ if self.raise_errors:
240
+ raise GreenAPIError(error_message)
241
+ self.logger.log(logging.ERROR, error_message)
242
+
243
+ return None
244
+
245
+ self.logger.log(
246
+ logging.DEBUG, f"Async request was successful with data: {data}"
247
+ )
248
+
249
+ def __prepare_logger(self) -> None:
250
+ handler = logging.StreamHandler()
251
+ handler.setFormatter(logging.Formatter(
252
+ (
253
+ "%(asctime)s:%(name)s:"
254
+ "%(levelname)s:%(message)s"
255
+ ), datefmt="%Y-%m-%d %H:%M:%S"
256
+ ))
257
+
258
+ self.logger.addHandler(handler)
259
+
260
+ if not self.debug_mode:
261
+ self.logger.setLevel(logging.INFO)
262
+ else:
263
+ self.logger.setLevel(logging.DEBUG)
264
+
265
+ def __prepare_session(self) -> None:
266
+ self.session.headers["Connection"] = "close"
267
+
268
+ retry = Retry(
269
+ total=3,
270
+ backoff_factor=1.0,
271
+ allowed_methods=None,
272
+ status_forcelist=[429]
273
+ )
274
+
275
+ self.session.mount("http://", HTTPAdapter(max_retries=retry))
276
+ self.session.mount("https://", HTTPAdapter(max_retries=retry))
277
+
278
+ class GreenAPI(GreenApi):
279
+ pass
280
+
281
+
282
+ class GreenAPIError(Exception):
283
+ pass
284
+
285
+ class GreenApiPartner(GreenApi):
286
+ def __init__(
287
+ self,
288
+ partnerToken: str,
289
+ email: str = None,
290
+ host: str = "https://api.green-api.com"
291
+ ):
292
+
293
+ super().__init__(
294
+ idInstance="",
295
+ apiTokenInstance="",
296
+ host=host
297
+ )
298
+
299
+ self.partnerToken = partnerToken
300
+ self.email = email
301
+ self.partner = partner.Partner(self)
302
+
303
+ def request(
304
+ self,
305
+ method: str,
306
+ url: str,
307
+ payload: Optional[dict] = None,
308
+ files: Optional[dict] = None
309
+ ) -> GreenAPIResponse:
310
+
311
+ url = url.replace("{{partnerToken}}", self.partnerToken)
312
+
313
+ return super().request(method, url, payload, files)
314
+
315
+ async def requestAsync(
316
+ self,
317
+ method: str,
318
+ url: str,
319
+ payload: Optional[dict] = None,
320
+ files: Optional[dict] = None
321
+ ) -> GreenAPIResponse:
322
+ url = url.replace("{{partnerToken}}", self.partnerToken)
323
+ return await super().requestAsync(method, url, payload, files)
File without changes
@@ -0,0 +1,18 @@
1
+ from json import loads
2
+ from typing import Optional
3
+
4
+
5
+ class Response:
6
+ code: Optional[int]
7
+ data: Optional[dict] = None
8
+ error: Optional[str] = None
9
+
10
+ def __init__(self, code: Optional[int], text: str):
11
+ self.code = code
12
+ if self.code == 200:
13
+ try:
14
+ self.data = loads(text)
15
+ except Exception:
16
+ self.data = "[]"
17
+ else:
18
+ self.error = text
File without changes
@@ -0,0 +1,261 @@
1
+ from pathlib import Path
2
+ from typing import Dict, TYPE_CHECKING, Optional, Union
3
+
4
+ import aiofiles
5
+
6
+ from ..response import Response
7
+
8
+ if TYPE_CHECKING:
9
+ from ..API import GreenApi
10
+
11
+
12
+ class Account:
13
+ def __init__(self, api: "GreenApi"):
14
+ self.api = api
15
+
16
+ def getSettings(self) -> Response:
17
+ """
18
+ The method is aimed for getting the current account settings.
19
+
20
+ https://green-api.com/telegram/docs/api/account/GetSettings/
21
+ """
22
+
23
+ return self.api.request(
24
+ "GET", (
25
+ "{{host}}/waInstance{{idInstance}}/"
26
+ "getSettings/{{apiTokenInstance}}"
27
+ )
28
+ )
29
+
30
+ async def getSettingsAsync(self) -> Response:
31
+ return await self.api.requestAsync(
32
+ "GET", "{{host}}/waInstance{{idInstance}}/getSettings/{{apiTokenInstance}}"
33
+ )
34
+
35
+ def getAccountSettings(self) -> Response:
36
+ """
37
+ The method is aimed to get information about the Account
38
+ account.
39
+
40
+ https://green-api.com/telegram/docs/api/account/getAccountSettings/
41
+ """
42
+
43
+ return self.api.request(
44
+ "GET", (
45
+ "{{host}}/waInstance{{idInstance}}/"
46
+ "getAccountSettings/{{apiTokenInstance}}"
47
+ )
48
+ )
49
+
50
+ async def getAccountSettingsAsync(self) -> Response:
51
+ return await self.api.requestAsync(
52
+ "GET", "{{host}}/waInstance{{idInstance}}/getAccountSettings/{{apiTokenInstance}}"
53
+ )
54
+
55
+ def setSettings(self, requestBody: Dict[str, Union[int, str]]) -> Response:
56
+ """
57
+ The method is aimed for setting account settings.
58
+
59
+ https://green-api.com/telegram/docs/api/account/SetSettings/
60
+ """
61
+
62
+ return self.api.request(
63
+ "POST", (
64
+ "{{host}}/waInstance{{idInstance}}/"
65
+ "setSettings/{{apiTokenInstance}}"
66
+ ), requestBody
67
+ )
68
+
69
+ async def setSettingsAsync(self, requestBody: Dict[str, Union[int, str]]) -> Response:
70
+ return await self.api.requestAsync(
71
+ "POST",
72
+ "{{host}}/waInstance{{idInstance}}/setSettings/{{apiTokenInstance}}",
73
+ requestBody
74
+ )
75
+
76
+
77
+ def getStateInstance(self) -> Response:
78
+ """
79
+ The method is aimed for getting the account state.
80
+
81
+ https://green-api.com/telegram/docs/api/account/GetStateInstance/
82
+ """
83
+
84
+ return self.api.request(
85
+ "GET", (
86
+ "{{host}}/waInstance{{idInstance}}/"
87
+ "getStateInstance/{{apiTokenInstance}}"
88
+ )
89
+ )
90
+
91
+ async def getStateInstanceAsync(self) -> Response:
92
+ return await self.api.requestAsync(
93
+ "GET", "{{host}}/waInstance{{idInstance}}/getStateInstance/{{apiTokenInstance}}"
94
+ )
95
+
96
+ def reboot(self) -> Response:
97
+ """
98
+ The method is aimed for rebooting an account.
99
+
100
+ https://green-api.com/telegram/docs/api/account/Reboot/
101
+ """
102
+
103
+ return self.api.request(
104
+ "GET", (
105
+ "{{host}}/waInstance{{idInstance}}/reboot/{{apiTokenInstance}}"
106
+ )
107
+ )
108
+
109
+ async def rebootAsync(self) -> Response:
110
+ return await self.api.requestAsync(
111
+ "GET", "{{host}}/waInstance{{idInstance}}/reboot/{{apiTokenInstance}}"
112
+ )
113
+
114
+ def logout(self) -> Response:
115
+ """
116
+ The method is aimed for logging out an account.
117
+
118
+ https://green-api.com/telegram/docs/api/account/Logout/
119
+ """
120
+
121
+ return self.api.request(
122
+ "GET", (
123
+ "{{host}}/waInstance{{idInstance}}/logout/{{apiTokenInstance}}"
124
+ )
125
+ )
126
+
127
+ async def logoutAsync(self) -> Response:
128
+ return await self.api.requestAsync(
129
+ "GET", "{{host}}/waInstance{{idInstance}}/logout/{{apiTokenInstance}}"
130
+ )
131
+
132
+ def qr(self) -> Response:
133
+ """
134
+ The method is aimed for getting QR code.
135
+
136
+ https://green-api.com/telegram/docs/api/account/QR/
137
+ """
138
+
139
+ return self.api.request(
140
+ "GET", "{{host}}/waInstance{{idInstance}}/qr/{{apiTokenInstance}}"
141
+ )
142
+
143
+ async def qrAsync(self) -> Response:
144
+ return await self.api.requestAsync(
145
+ "GET", "{{host}}/waInstance{{idInstance}}/qr/{{apiTokenInstance}}"
146
+ )
147
+
148
+ def setProfilePicture(self, path: str) -> Response:
149
+ """
150
+ The method is aimed for setting an account picture.
151
+
152
+ https://green-api.com/telegram/docs/api/account/SetProfilePicture/
153
+ """
154
+
155
+ file_name = Path(path).name
156
+ files = {"file": (file_name, open(path, "rb"), "image/jpeg")}
157
+
158
+ return self.api.request(
159
+ "POST", (
160
+ "{{host}}/waInstance{{idInstance}}/"
161
+ "setProfilePicture/{{apiTokenInstance}}"
162
+ ), files=files
163
+ )
164
+
165
+ async def setProfilePictureAsync(self, path: str) -> Response:
166
+ file_name = Path(path).name
167
+ async with aiofiles.open(path, "rb") as file:
168
+ file_data = await file.read()
169
+ files = {"file": (file_name, file_data, "image/jpeg")}
170
+
171
+ return await self.api.requestAsync(
172
+ "POST",
173
+ "{{host}}/waInstance{{idInstance}}/setProfilePicture/{{apiTokenInstance}}",
174
+ files=files
175
+ )
176
+
177
+
178
+ def startAuthorization(self, phoneNumber: int) -> Response:
179
+ """
180
+ The method is designed to receive code for instance authorization.
181
+
182
+ https://green-api.com/telegram/docs/api/account/StartAuthorization/
183
+ """
184
+
185
+ request_body = locals()
186
+ request_body.pop("self")
187
+
188
+ return self.api.request(
189
+ "POST", (
190
+ "{{host}}/waInstance{{idInstance}}/"
191
+ "startAuthorization/{{apiTokenInstance}}"
192
+ ), request_body
193
+ )
194
+
195
+ async def startAuthorizationAsync(self, phoneNumber: int) -> Response:
196
+ request_body = locals()
197
+ request_body.pop("self")
198
+
199
+ return await self.api.requestAsync(
200
+ "POST",
201
+ "{{host}}/waInstance{{idInstance}}/startAuthorization/{{apiTokenInstance}}",
202
+ request_body
203
+ )
204
+
205
+ def sendAuthorizationCode(self, code: str, password: Optional[str] = None) -> Response:
206
+ """
207
+ The method is designed to receive code for instance authorization.
208
+
209
+ https://green-api.com/telegram/docs/api/account/SendAuthorizationCode/
210
+ """
211
+
212
+ request_body = locals()
213
+ if password is None:
214
+ request_body.pop("password")
215
+ request_body.pop("self")
216
+
217
+ return self.api.request(
218
+ "POST", (
219
+ "{{host}}/waInstance{{idInstance}}/"
220
+ "sendAuthorizationCode/{{apiTokenInstance}}"
221
+ ), request_body
222
+ )
223
+
224
+ async def sendAuthorizationCodeAsync(self, code: str, password: Optional[str] = None) -> Response:
225
+ request_body = locals()
226
+ if password is None:
227
+ request_body.pop("password")
228
+ request_body.pop("self")
229
+
230
+ return await self.api.requestAsync(
231
+ "POST",
232
+ "{{host}}/waInstance{{idInstance}}/sendAuthorizationCode/{{apiTokenInstance}}",
233
+ request_body
234
+ )
235
+
236
+ def sendAuthorizationPassword(self, password: str) -> Response:
237
+ """
238
+ The method is designed to receive code for instance authorization.
239
+
240
+ https://green-api.com/telegram/docs/api/account/SendAuthorizationPassword/
241
+ """
242
+
243
+ request_body = locals()
244
+ request_body.pop("self")
245
+
246
+ return self.api.request(
247
+ "POST", (
248
+ "{{host}}/waInstance{{idInstance}}/"
249
+ "sendAuthorizationPassword/{{apiTokenInstance}}"
250
+ ), request_body
251
+ )
252
+
253
+ async def sendAuthorizationPasswordAsync(self, password: str) -> Response:
254
+ request_body = locals()
255
+ request_body.pop("self")
256
+
257
+ return await self.api.requestAsync(
258
+ "POST",
259
+ "{{host}}/waInstance{{idInstance}}/sendAuthorizationPassword/{{apiTokenInstance}}",
260
+ request_body
261
+ )