pyaterochka-api 0.1.6__tar.gz → 0.1.7__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyaterochka_api
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A Python API client for Pyaterochka store catalog
5
5
  Home-page: https://github.com/Open-Inflation/pyaterochka_api
6
6
  Author: Miskler
@@ -22,6 +22,7 @@ Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: aiohttp
24
24
  Requires-Dist: camoufox[geoip]
25
+ Requires-Dist: beartype
25
26
  Requires-Dist: fake-useragent
26
27
  Requires-Dist: tqdm
27
28
  Provides-Extra: tests
@@ -43,6 +44,7 @@ Dynamic: summary
43
44
 
44
45
  Pyaterochka (Пятёрочка) - https://5ka.ru/
45
46
 
47
+ [![GitHub Actions](https://github.com/Open-Inflation/pyaterochka_api/workflows/API%20Tests%20Daily/badge.svg)](https://github.com/Open-Inflation/pyaterochka_api/actions?query=workflow%3A"API+Tests+Daily?query=branch%3Amain")
46
48
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyaterochka_api)
47
49
  ![PyPI - Package Version](https://img.shields.io/pypi/v/pyaterochka_api?color=blue)
48
50
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/pyaterochka_api?label=PyPi%20downloads)](https://pypi.org/project/pyaterochka-api/)
@@ -72,7 +74,7 @@ import asyncio
72
74
 
73
75
 
74
76
  async def main():
75
- async with Pyaterochka(proxy="user:password@host:port", debug=False, autoclose_browser=False) as API:
77
+ async with Pyaterochka(proxy="user:password@host:port", debug=False, autoclose_browser=False, trust_env=False) as API:
76
78
  # RUS: Вводим геоточку (самого магазина или рядом с ним) и получаем инфу о магазине
77
79
  # ENG: Enter a geolocation (of the store or near it) and get info about the store
78
80
  find_store = await API.find_store(longitude=37.63156, latitude=55.73768)
@@ -102,6 +104,12 @@ async def main():
102
104
  # I do not recommend enabling it, if you still need to free up memory, it is better to use API.close(session=False, browser=True)
103
105
  API.autoclose_browser = True
104
106
 
107
+ # RUS: Напрямую передается в aiohttp, так же учитывается в браузере. В первую очередь нужен для использования системного `HTTPS_PROXY`.
108
+ # Но системный прокси применяется, только если не указали иное напрямую в `API.proxy`.
109
+ # ENG: Directly passed to aiohttp, also taken into account in the browser. Primarily needed for using the system `HTTPS_PROXY`.
110
+ # But the system proxy is applied only if you did not specify otherwise directly in `API.proxy`.
111
+ API.trust_env = True
112
+
105
113
  # RUS: Выводит список последних промо-акций/новостей (можно поставить ограничитель по количеству, опционально)
106
114
  # ENG: Outputs a list of the latest promotions/news (you can set a limit on the number, optionally)
107
115
  news = await API.get_news(limit=5)
@@ -121,13 +129,17 @@ async def main():
121
129
  with open(image.name, 'wb') as f:
122
130
  f.write(image.getbuffer())
123
131
 
132
+ # RUS: Можно указать свой таймаут (браузер может его интерпретировать как x2 т.к. там 2 итерации скачивания)
133
+ # ENG: You can specify your own timeout (the browser may interpret it as x2 since there are 2 iterations of downloading)
134
+ API.timeout = 7
135
+
124
136
  # RUS: Так же как и debug, в рантайме можно переназначить прокси
125
137
  # ENG: As with debug, you can reassign the proxy in runtime
126
138
  API.proxy = "user:password@host:port"
127
- # RUS: Чтобы применить изменения, нужно пересоздать подключение (session - aiohttp отвечающее за все, кроме product_info, за него browser)
128
- # ENG: To apply changes, you need rebuild connection (session - aiohttp responsible for everything except product_info, for it browser)
129
- await API.rebuild_connection()
130
- await API.categories_list()
139
+ # RUS: Изменения происходят сразу же, кроме product_info, т.к. за него отвечает браузер
140
+ # ENG: Changes take effect immediately, except for product_info, as it is handled by the browser
141
+ await API.rebuild_connection(session=False, browser=True)
142
+ await API.product_info(43347)
131
143
 
132
144
 
133
145
  if __name__ == '__main__':
@@ -2,6 +2,7 @@
2
2
 
3
3
  Pyaterochka (Пятёрочка) - https://5ka.ru/
4
4
 
5
+ [![GitHub Actions](https://github.com/Open-Inflation/pyaterochka_api/workflows/API%20Tests%20Daily/badge.svg)](https://github.com/Open-Inflation/pyaterochka_api/actions?query=workflow%3A"API+Tests+Daily?query=branch%3Amain")
5
6
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyaterochka_api)
6
7
  ![PyPI - Package Version](https://img.shields.io/pypi/v/pyaterochka_api?color=blue)
7
8
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/pyaterochka_api?label=PyPi%20downloads)](https://pypi.org/project/pyaterochka-api/)
@@ -31,7 +32,7 @@ import asyncio
31
32
 
32
33
 
33
34
  async def main():
34
- async with Pyaterochka(proxy="user:password@host:port", debug=False, autoclose_browser=False) as API:
35
+ async with Pyaterochka(proxy="user:password@host:port", debug=False, autoclose_browser=False, trust_env=False) as API:
35
36
  # RUS: Вводим геоточку (самого магазина или рядом с ним) и получаем инфу о магазине
36
37
  # ENG: Enter a geolocation (of the store or near it) and get info about the store
37
38
  find_store = await API.find_store(longitude=37.63156, latitude=55.73768)
@@ -61,6 +62,12 @@ async def main():
61
62
  # I do not recommend enabling it, if you still need to free up memory, it is better to use API.close(session=False, browser=True)
62
63
  API.autoclose_browser = True
63
64
 
65
+ # RUS: Напрямую передается в aiohttp, так же учитывается в браузере. В первую очередь нужен для использования системного `HTTPS_PROXY`.
66
+ # Но системный прокси применяется, только если не указали иное напрямую в `API.proxy`.
67
+ # ENG: Directly passed to aiohttp, also taken into account in the browser. Primarily needed for using the system `HTTPS_PROXY`.
68
+ # But the system proxy is applied only if you did not specify otherwise directly in `API.proxy`.
69
+ API.trust_env = True
70
+
64
71
  # RUS: Выводит список последних промо-акций/новостей (можно поставить ограничитель по количеству, опционально)
65
72
  # ENG: Outputs a list of the latest promotions/news (you can set a limit on the number, optionally)
66
73
  news = await API.get_news(limit=5)
@@ -80,13 +87,17 @@ async def main():
80
87
  with open(image.name, 'wb') as f:
81
88
  f.write(image.getbuffer())
82
89
 
90
+ # RUS: Можно указать свой таймаут (браузер может его интерпретировать как x2 т.к. там 2 итерации скачивания)
91
+ # ENG: You can specify your own timeout (the browser may interpret it as x2 since there are 2 iterations of downloading)
92
+ API.timeout = 7
93
+
83
94
  # RUS: Так же как и debug, в рантайме можно переназначить прокси
84
95
  # ENG: As with debug, you can reassign the proxy in runtime
85
96
  API.proxy = "user:password@host:port"
86
- # RUS: Чтобы применить изменения, нужно пересоздать подключение (session - aiohttp отвечающее за все, кроме product_info, за него browser)
87
- # ENG: To apply changes, you need rebuild connection (session - aiohttp responsible for everything except product_info, for it browser)
88
- await API.rebuild_connection()
89
- await API.categories_list()
97
+ # RUS: Изменения происходят сразу же, кроме product_info, т.к. за него отвечает браузер
98
+ # ENG: Changes take effect immediately, except for product_info, as it is handled by the browser
99
+ await API.rebuild_connection(session=False, browser=True)
100
+ await API.product_info(43347)
90
101
 
91
102
 
92
103
  if __name__ == '__main__':
@@ -4,6 +4,7 @@ from enum import Enum
4
4
  import re
5
5
  from tqdm.asyncio import tqdm
6
6
  from camoufox import AsyncCamoufox
7
+ import os
7
8
 
8
9
 
9
10
  class PyaterochkaAPI:
@@ -18,13 +19,15 @@ class PyaterochkaAPI:
18
19
  LIST = r'(\w+)\s*:\s*\[([^\[\]]*(?:\[.*?\])*)\]' # key: [value]
19
20
  FIND = r'\{.*?\}|\[.*?\]' # {} or []
20
21
 
21
- def __init__(self, debug: bool = False, proxy: str = None, autoclose_browser: bool = False):
22
+ def __init__(self, debug: bool = False, proxy: str = None, autoclose_browser: bool = False, trust_env: bool = False, timeout: int = 10):
22
23
  self._debug = debug
23
24
  self._proxy = proxy
24
25
  self._session = None
25
26
  self._autoclose_browser = autoclose_browser
26
27
  self._browser = None
27
28
  self._bcontext = None
29
+ self._trust_env = trust_env
30
+ self._timeout = timeout
28
31
 
29
32
  @property
30
33
  def proxy(self) -> str | None:
@@ -38,12 +41,15 @@ class PyaterochkaAPI:
38
41
  """
39
42
  Выполняет HTTP-запрос к указанному URL и возвращает результат.
40
43
 
41
- :return: Кортеж (успех, данные или None).
44
+ :return: Кортеж (успех, данные или None, тип данных или пустота).
42
45
  """
43
- if self._debug:
44
- print(f"Requesting \"{url}\"...", flush=True)
46
+ args = {'url': url, 'timeout': aiohttp.ClientTimeout(total=self._timeout)}
47
+ if self._proxy: args["proxy"] = self._proxy
45
48
 
46
- async with self._session.get(url=url) as response:
49
+ if self._debug:
50
+ print(f"Requesting \"{url}\" with proxy \"{args.get('proxy')}\", timeout {self._timeout}...", flush=True)
51
+
52
+ async with self._session.get(**args) as response:
47
53
  if self._debug:
48
54
  print(f"Response status: {response.status}", flush=True)
49
55
 
@@ -154,9 +160,9 @@ class PyaterochkaAPI:
154
160
  await self._new_session(include_aiohttp=False, include_browser=True)
155
161
 
156
162
  page = await self._bcontext.new_page()
157
- await page.goto(url, wait_until='commit')
163
+ await page.goto(url, wait_until='commit', timeout=self._timeout * 1000)
158
164
  # Wait until the selector script tag appears
159
- await page.wait_for_selector(selector=selector, state=state)
165
+ await page.wait_for_selector(selector=selector, state=state, timeout=self._timeout * 1000)
160
166
  content = await page.content()
161
167
  await page.close()
162
168
 
@@ -166,7 +172,11 @@ class PyaterochkaAPI:
166
172
 
167
173
  def _parse_proxy(self, proxy_str: str | None) -> dict | None:
168
174
  if not proxy_str:
169
- return None
175
+ if self._trust_env:
176
+ proxy_str = os.environ.get("HTTPS_PROXY") or os.environ.get("https_proxy")
177
+
178
+ if not proxy_str:
179
+ return None
170
180
 
171
181
  # Example: user:pass@host:port or just host:port
172
182
  match = re.match(
@@ -196,17 +206,35 @@ class PyaterochkaAPI:
196
206
  await self.close(include_aiohttp=include_aiohttp, include_browser=include_browser)
197
207
 
198
208
  if include_aiohttp:
199
- args = {"headers": {"User-Agent": UserAgent().random}}
200
- if self._proxy: args["proxy"] = self._proxy
209
+ args = {
210
+ "headers": {
211
+ "User-Agent": UserAgent().random,
212
+ "Accept": "application/json, text/plain, */*",
213
+ "Accept-Language": "en-GB,en;q=0.5",
214
+ "Accept-Encoding": "gzip, deflate, br, zstd",
215
+ "X-PLATFORM": "webapp",
216
+ "Origin": "https://5ka.ru",
217
+ "Connection": "keep-alive",
218
+ "Sec-Fetch-Dest": "empty",
219
+ "Sec-Fetch-Mode": "cors",
220
+ "Sec-Fetch-Site": "same-site",
221
+ "Pragma": "no-cache",
222
+ "Cache-Control": "no-cache",
223
+ "TE": "trailers",
224
+ },
225
+ "trust_env": self._trust_env,
226
+ }
201
227
  self._session = aiohttp.ClientSession(**args)
202
228
 
203
- if self._debug: print(f"A new connection aiohttp has been opened. Proxy used: {args.get('proxy')}")
229
+ if self._debug: print(f"A new connection aiohttp has been opened. trust_env: {args.get('trust_env')}")
204
230
 
205
231
  if include_browser:
206
- self._browser = await AsyncCamoufox(headless=not self._debug, proxy=self._parse_proxy(self.proxy), geoip=True).__aenter__()
232
+ prox = self._parse_proxy(self.proxy)
233
+ self._browser = await AsyncCamoufox(headless=not self._debug, proxy=prox, geoip=True).__aenter__()
207
234
  self._bcontext = await self._browser.new_context()
208
235
 
209
- if self._debug: print(f"A new connection browser has been opened. Proxy used: {self.proxy}")
236
+ toprint = "SYSTEM_PROXY" if prox and not self.proxy else prox
237
+ if self._debug: print(f"A new connection browser has been opened. Proxy used: {toprint}")
210
238
 
211
239
  async def close(
212
240
  self,
@@ -3,6 +3,7 @@ from enum import Enum
3
3
  import re
4
4
  import json
5
5
  from io import BytesIO
6
+ from beartype import beartype
6
7
 
7
8
 
8
9
  class Pyaterochka:
@@ -15,24 +16,30 @@ class Pyaterochka:
15
16
  STORE = "store"
16
17
  DELIVERY = "delivery"
17
18
 
18
- def __init__(self, debug: bool = False, proxy: str = None, autoclose_browser: bool = False):
19
+ @beartype
20
+ def __init__(self, debug: bool = False, proxy: str = None, autoclose_browser: bool = False, trust_env: bool = False, timeout: int = 10):
19
21
  self._debug = debug
20
22
  self._proxy = proxy
21
- self.api = PyaterochkaAPI(debug=self._debug, proxy=self._proxy, autoclose_browser=autoclose_browser)
23
+ self.api = PyaterochkaAPI(debug=self._debug, proxy=self._proxy, autoclose_browser=autoclose_browser, trust_env=trust_env, timeout=timeout)
22
24
 
25
+ @beartype
23
26
  def __enter__(self):
24
27
  raise NotImplementedError("Use `async with Pyaterochka() as ...:`")
25
28
 
29
+ @beartype
26
30
  def __exit__(self, exc_type, exc_val, exc_tb):
27
31
  pass
28
32
 
33
+ @beartype
29
34
  async def __aenter__(self):
30
- await self.rebuild_connection(session=True)
35
+ await self.rebuild_connection(session=True, browser=False)
31
36
  return self
32
37
 
38
+ @beartype
33
39
  async def __aexit__(self, exc_type, exc_val, exc_tb):
34
40
  await self.close()
35
41
 
42
+ @beartype
36
43
  async def rebuild_connection(self, session: bool = True, browser: bool = False) -> None:
37
44
  """
38
45
  Rebuilds the connection to the Pyaterochka API.
@@ -42,6 +49,7 @@ class Pyaterochka:
42
49
  """
43
50
  await self.api._new_session(session, browser)
44
51
 
52
+ @beartype
45
53
  async def close(self, session: bool = True, browser: bool = True) -> None:
46
54
  """
47
55
  Closes the connection to the Pyaterochka API.
@@ -52,43 +60,74 @@ class Pyaterochka:
52
60
  await self.api.close(include_aiohttp=session, include_browser=browser)
53
61
 
54
62
  @property
63
+ @beartype
55
64
  def debug(self) -> bool:
56
65
  """If True, it will print debug messages and disable headless in browser."""
57
66
  return self._debug
58
67
 
59
68
  @debug.setter
69
+ @beartype
60
70
  def debug(self, value: bool):
61
71
  self._debug = value
62
72
  self.api.debug = value
63
73
 
64
74
  @property
75
+ @beartype
65
76
  def proxy(self) -> str:
66
77
  """Proxy for requests. If None, it will be used without proxy."""
67
78
  return self._proxy
68
79
 
69
80
  @proxy.setter
81
+ @beartype
70
82
  def proxy(self, value: str):
71
83
  self._proxy = value
72
84
  self.api.proxy = value
73
85
 
74
86
  @property
87
+ @beartype
75
88
  def autoclose_browser(self) -> bool:
76
89
  """If True, the browser closes after each request, clearing all cookies and caches.
77
90
  If you have more than one request and this function is enabled, the processing speed will be greatly affected! (all caches are recreated every time)"""
78
91
  return self.api._autoclose_browser
79
92
 
80
- @proxy.setter
93
+ @autoclose_browser.setter
94
+ @beartype
81
95
  def autoclose_browser(self, value: bool):
82
96
  self.api._autoclose_browser = value
97
+
98
+ @property
99
+ @beartype
100
+ def trust_env(self) -> bool:
101
+ """Passed directly to aiohttp. Also, if no proxy is specified, the system proxy (variable HTTPS_PROXY) will be used for the browser."""
102
+ return self.api._trust_env
103
+
104
+ @trust_env.setter
105
+ @beartype
106
+ def trust_env(self, value: bool):
107
+ self.api._trust_env = value
108
+
109
+ @property
110
+ @beartype
111
+ def timeout(self) -> int:
112
+ """Timeout value for the API requests."""
113
+ return self.api._timeout
114
+
115
+ @trust_env.setter
116
+ @beartype
117
+ def timeout(self, value: int):
118
+ if value <= 0:
119
+ raise ValueError("Timeout must be greater than 0")
83
120
 
121
+ self.api._timeout = value
84
122
 
123
+ @beartype
85
124
  async def categories_list(
86
125
  self,
87
126
  subcategories: bool = False,
88
127
  include_restrict: bool = True,
89
128
  mode: PurchaseMode = PurchaseMode.STORE,
90
129
  sap_code_store_id: str = DEFAULT_STORE_ID
91
- ) -> dict | None:
130
+ ) -> list[dict] | None:
92
131
  f"""
93
132
  Asynchronously retrieves a list of categories from the Pyaterochka API.
94
133
 
@@ -109,9 +148,10 @@ class Pyaterochka:
109
148
  _is_success, response, _response_type = await self.api.fetch(url=request_url)
110
149
  return response
111
150
 
151
+ @beartype
112
152
  async def products_list(
113
153
  self,
114
- category_id: int,
154
+ category_id: str,
115
155
  mode: PurchaseMode = PurchaseMode.STORE,
116
156
  sap_code_store_id: str = DEFAULT_STORE_ID,
117
157
  limit: int = 30
@@ -120,7 +160,7 @@ class Pyaterochka:
120
160
  Asynchronously retrieves a list of products from the Pyaterochka API for a given category.
121
161
 
122
162
  Args:
123
- category_id (int): The ID of the category.
163
+ category_id (str): The ID of the (sub)category.
124
164
  mode (PurchaseMode, optional): The purchase mode to use. Defaults to PurchaseMode.STORE.
125
165
  sap_code_store_id (str, optional): The store ID (official name in API is "sap_code") to use. Defaults to "{self.DEFAULT_STORE_ID}". This lib not support search ID stores.
126
166
  limit (int, optional): The maximum number of products to retrieve. Defaults to 30. Must be between 1 and 499.
@@ -140,6 +180,7 @@ class Pyaterochka:
140
180
  _is_success, response, _response_type = await self.api.fetch(url=request_url)
141
181
  return response
142
182
 
183
+ @beartype
143
184
  async def product_info(self, plu_id: int) -> dict:
144
185
  """
145
186
  Asynchronously retrieves product information from the Pyaterochka API for a given PLU ID. Average time processing 2 seconds (first start 6 seconds).
@@ -169,6 +210,7 @@ class Pyaterochka:
169
210
 
170
211
  return data
171
212
 
213
+ @beartype
172
214
  async def get_news(self, limit: int = None) -> dict | None:
173
215
  """
174
216
  Asynchronously retrieves news from the Pyaterochka API.
@@ -187,6 +229,7 @@ class Pyaterochka:
187
229
 
188
230
  return response
189
231
 
232
+ @beartype
190
233
  async def find_store(self, longitude: float, latitude: float) -> dict | None:
191
234
  """
192
235
  Asynchronously finds the store associated with the given coordinates.
@@ -203,6 +246,7 @@ class Pyaterochka:
203
246
  _is_success, response, _response_type = await self.api.fetch(url=request_url)
204
247
  return response
205
248
 
249
+ @beartype
206
250
  async def download_image(self, url: str) -> BytesIO | None:
207
251
  is_success, image_data, response_type = await self.api.fetch(url=url)
208
252
 
@@ -218,7 +262,8 @@ class Pyaterochka:
218
262
 
219
263
  return image
220
264
 
221
- async def get_config(self) -> list | None:
265
+ @beartype
266
+ async def get_config(self) -> dict | None:
222
267
  """
223
268
  Asynchronously retrieves the configuration from the hardcoded JavaScript file.
224
269
 
@@ -226,7 +271,7 @@ class Pyaterochka:
226
271
  debug (bool, optional): Whether to print debug information. Defaults to False.
227
272
 
228
273
  Returns:
229
- list | None: A list representing the configuration if the request is successful, None otherwise.
274
+ dict | None: A dictionary representing the configuration if the request is successful, None otherwise.
230
275
  """
231
276
 
232
277
  return await self.api.download_config(config_url=self.HARDCODE_JS_CONFIG)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyaterochka_api
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A Python API client for Pyaterochka store catalog
5
5
  Home-page: https://github.com/Open-Inflation/pyaterochka_api
6
6
  Author: Miskler
@@ -22,6 +22,7 @@ Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: aiohttp
24
24
  Requires-Dist: camoufox[geoip]
25
+ Requires-Dist: beartype
25
26
  Requires-Dist: fake-useragent
26
27
  Requires-Dist: tqdm
27
28
  Provides-Extra: tests
@@ -43,6 +44,7 @@ Dynamic: summary
43
44
 
44
45
  Pyaterochka (Пятёрочка) - https://5ka.ru/
45
46
 
47
+ [![GitHub Actions](https://github.com/Open-Inflation/pyaterochka_api/workflows/API%20Tests%20Daily/badge.svg)](https://github.com/Open-Inflation/pyaterochka_api/actions?query=workflow%3A"API+Tests+Daily?query=branch%3Amain")
46
48
  ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyaterochka_api)
47
49
  ![PyPI - Package Version](https://img.shields.io/pypi/v/pyaterochka_api?color=blue)
48
50
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/pyaterochka_api?label=PyPi%20downloads)](https://pypi.org/project/pyaterochka-api/)
@@ -72,7 +74,7 @@ import asyncio
72
74
 
73
75
 
74
76
  async def main():
75
- async with Pyaterochka(proxy="user:password@host:port", debug=False, autoclose_browser=False) as API:
77
+ async with Pyaterochka(proxy="user:password@host:port", debug=False, autoclose_browser=False, trust_env=False) as API:
76
78
  # RUS: Вводим геоточку (самого магазина или рядом с ним) и получаем инфу о магазине
77
79
  # ENG: Enter a geolocation (of the store or near it) and get info about the store
78
80
  find_store = await API.find_store(longitude=37.63156, latitude=55.73768)
@@ -102,6 +104,12 @@ async def main():
102
104
  # I do not recommend enabling it, if you still need to free up memory, it is better to use API.close(session=False, browser=True)
103
105
  API.autoclose_browser = True
104
106
 
107
+ # RUS: Напрямую передается в aiohttp, так же учитывается в браузере. В первую очередь нужен для использования системного `HTTPS_PROXY`.
108
+ # Но системный прокси применяется, только если не указали иное напрямую в `API.proxy`.
109
+ # ENG: Directly passed to aiohttp, also taken into account in the browser. Primarily needed for using the system `HTTPS_PROXY`.
110
+ # But the system proxy is applied only if you did not specify otherwise directly in `API.proxy`.
111
+ API.trust_env = True
112
+
105
113
  # RUS: Выводит список последних промо-акций/новостей (можно поставить ограничитель по количеству, опционально)
106
114
  # ENG: Outputs a list of the latest promotions/news (you can set a limit on the number, optionally)
107
115
  news = await API.get_news(limit=5)
@@ -121,13 +129,17 @@ async def main():
121
129
  with open(image.name, 'wb') as f:
122
130
  f.write(image.getbuffer())
123
131
 
132
+ # RUS: Можно указать свой таймаут (браузер может его интерпретировать как x2 т.к. там 2 итерации скачивания)
133
+ # ENG: You can specify your own timeout (the browser may interpret it as x2 since there are 2 iterations of downloading)
134
+ API.timeout = 7
135
+
124
136
  # RUS: Так же как и debug, в рантайме можно переназначить прокси
125
137
  # ENG: As with debug, you can reassign the proxy in runtime
126
138
  API.proxy = "user:password@host:port"
127
- # RUS: Чтобы применить изменения, нужно пересоздать подключение (session - aiohttp отвечающее за все, кроме product_info, за него browser)
128
- # ENG: To apply changes, you need rebuild connection (session - aiohttp responsible for everything except product_info, for it browser)
129
- await API.rebuild_connection()
130
- await API.categories_list()
139
+ # RUS: Изменения происходят сразу же, кроме product_info, т.к. за него отвечает браузер
140
+ # ENG: Changes take effect immediately, except for product_info, as it is handled by the browser
141
+ await API.rebuild_connection(session=False, browser=True)
142
+ await API.product_info(43347)
131
143
 
132
144
 
133
145
  if __name__ == '__main__':
@@ -1,5 +1,6 @@
1
1
  aiohttp
2
2
  camoufox[geoip]
3
+ beartype
3
4
  fake-useragent
4
5
  tqdm
5
6
 
@@ -2,11 +2,12 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='pyaterochka_api',
5
- version='0.1.6',
5
+ version='0.1.7',
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  'aiohttp',
9
9
  'camoufox[geoip]',
10
+ 'beartype',
10
11
  'fake-useragent',
11
12
  'tqdm'
12
13
  ],
@@ -14,7 +14,7 @@ def gen_schema(data):
14
14
 
15
15
  @pytest.mark.asyncio
16
16
  async def test_list(snapshot: SnapshotTest):
17
- async with Pyaterochka() as API:
17
+ async with Pyaterochka(debug=True, trust_env=True) as API:
18
18
  categories = await API.categories_list(subcategories=True)
19
19
  snapshot.assert_match(gen_schema(categories), "categories_list")
20
20
 
@@ -23,25 +23,25 @@ async def test_list(snapshot: SnapshotTest):
23
23
 
24
24
  @pytest.mark.asyncio
25
25
  async def test_product_info(snapshot: SnapshotTest):
26
- async with Pyaterochka() as API:
26
+ async with Pyaterochka(trust_env=True) as API:
27
27
  result = await API.product_info(43347)
28
28
  snapshot.assert_match(gen_schema(result), "product_info")
29
29
 
30
30
  @pytest.mark.asyncio
31
31
  async def test_get_news(snapshot: SnapshotTest):
32
- async with Pyaterochka() as API:
32
+ async with Pyaterochka(debug=True, trust_env=True) as API:
33
33
  result = await API.get_news(limit=5)
34
34
  snapshot.assert_match(gen_schema(result), "get_news")
35
35
 
36
36
  @pytest.mark.asyncio
37
37
  async def test_find_store(snapshot: SnapshotTest):
38
- async with Pyaterochka() as API:
38
+ async with Pyaterochka(debug=True, trust_env=True) as API:
39
39
  categories = await API.find_store(longitude=37.63156, latitude=55.73768)
40
40
  snapshot.assert_match(gen_schema(categories), "store_info")
41
41
 
42
42
  @pytest.mark.asyncio
43
43
  async def test_download_image(snapshot: SnapshotTest):
44
- async with Pyaterochka() as API:
44
+ async with Pyaterochka(debug=True, trust_env=True) as API:
45
45
  result = await API.download_image("https://photos.okolo.app/product/1392827-main/800x800.jpeg")
46
46
  assert isinstance(result, BytesIO)
47
47
  assert result.getvalue()
@@ -55,12 +55,12 @@ async def test_set_debug(snapshot: SnapshotTest):
55
55
 
56
56
  @pytest.mark.asyncio
57
57
  async def test_rebuild_connection(snapshot: SnapshotTest):
58
- async with Pyaterochka() as API:
58
+ async with Pyaterochka(debug=True, trust_env=True) as API:
59
59
  await API.rebuild_connection()
60
60
  snapshot.assert_match("connection has been rebuilt", "rebuild_connection")
61
61
 
62
- @pytest.mark.asyncio
63
- async def test_get_config(snapshot: SnapshotTest):
64
- async with Pyaterochka() as API:
65
- result = await API.get_config()
66
- snapshot.assert_match(gen_schema(result), "get_config")
62
+ #@pytest.mark.asyncio
63
+ #async def test_get_config(snapshot: SnapshotTest):
64
+ # async with Pyaterochka(debug=True, trust_env=True, timeout=30) as API:
65
+ # result = await API.get_config()
66
+ # snapshot.assert_match(gen_schema(result), "get_config")
File without changes