pyaterochka-api 0.1.9.1__py3-none-any.whl → 0.2.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.
@@ -1,4 +1,5 @@
1
1
  from .manager import Pyaterochka
2
2
  from .enums import PurchaseMode
3
3
 
4
+ __version__ = "0.2.0"
4
5
  __all__ = ['Pyaterochka', 'PurchaseMode']
pyaterochka_api/api.py CHANGED
@@ -2,7 +2,9 @@ import aiohttp
2
2
  from fake_useragent import UserAgent
3
3
  from camoufox import AsyncCamoufox
4
4
  import logging
5
- from .tools import parse_proxy, parse_js, get_env_proxy
5
+ from typing import Union, Optional
6
+ from beartype import beartype
7
+ from .tools import parse_proxy, get_env_proxy
6
8
 
7
9
 
8
10
  class PyaterochkaAPI:
@@ -10,16 +12,17 @@ class PyaterochkaAPI:
10
12
  Класс для загрузки JSON/image и парсинга JavaScript-конфигураций из удаленного источника.
11
13
  """
12
14
 
15
+ @beartype
13
16
  def __init__(self,
14
17
  debug: bool = False,
15
18
  proxy: str | None = None,
16
19
  autoclose_browser: bool = False,
17
20
  trust_env: bool = False,
18
21
  timeout: float = 10.0
19
- ):
22
+ ) -> None:
20
23
  self._debug = debug
21
24
  self._proxy = proxy
22
- self._session = None
25
+ self._session: Optional[aiohttp.ClientSession] = None
23
26
  self._autoclose_browser = autoclose_browser
24
27
  self._browser = None
25
28
  self._bcontext = None
@@ -33,7 +36,8 @@ class PyaterochkaAPI:
33
36
  if not self._logger.hasHandlers():
34
37
  self._logger.addHandler(handler)
35
38
 
36
- async def fetch(self, url: str) -> tuple[bool, dict | None | str, str]:
39
+ @beartype
40
+ async def fetch(self, url: str) -> tuple[bool, Union[dict, list[dict], bytes, str, None], str]:
37
41
  """
38
42
  Выполняет HTTP-запрос к указанному URL и возвращает результат.
39
43
 
@@ -63,26 +67,8 @@ class PyaterochkaAPI:
63
67
  self._logger.error(f'Unexpected error: {response.status}')
64
68
  raise Exception(f"Response status: {response.status} (unknown error/status code)")
65
69
 
66
- async def download_config(self, config_url: str) -> dict | None:
67
- """
68
- Загружает и парсит JavaScript-конфигурацию с указанного URL.
69
-
70
- :param config_url: URL для загрузки конфигурации.
71
- :return: Распарсенные данные в виде словаря или None.
72
- """
73
- is_success, js_code, _response_type = await self.fetch(url=config_url)
74
-
75
- if not is_success:
76
- if self._debug:
77
- self._logger.error('Failed to fetch JS code')
78
- return None
79
- elif self._debug:
80
- self._logger.debug('JS code fetched successfully')
81
-
82
- return await parse_js(js_code=js_code, debug=self._debug, logger=self._logger)
83
-
84
-
85
- async def browser_fetch(self, url: str, selector: str, state: str = 'attached') -> dict:
70
+ @beartype
71
+ async def browser_fetch(self, url: str, selector: str, state: str = 'attached') -> str:
86
72
  if self._browser is None or self._bcontext is None:
87
73
  await self.new_session(include_aiohttp=False, include_browser=True)
88
74
 
@@ -97,6 +83,7 @@ class PyaterochkaAPI:
97
83
  await self.close(include_aiohttp=False, include_browser=True)
98
84
  return content
99
85
 
86
+ @beartype
100
87
  async def new_session(self, include_aiohttp: bool = True, include_browser: bool = False) -> None:
101
88
  await self.close(include_aiohttp=include_aiohttp, include_browser=include_browser)
102
89
 
@@ -129,6 +116,7 @@ class PyaterochkaAPI:
129
116
  self._bcontext = await self._browser.new_context()
130
117
  self._logger.info(f"A new browser context has been opened.")
131
118
 
119
+ @beartype
132
120
  async def close(
133
121
  self,
134
122
  include_aiohttp: bool = True,
pyaterochka_api/enums.py CHANGED
@@ -1,11 +1,6 @@
1
1
  from enum import Enum
2
2
 
3
3
  class Patterns(Enum):
4
- JS = r'\s*let\s+n\s*=\s*({.*});\s*' # let n = {...};
5
- STR = r'(\w+)\s*:\s*"([^"\\]*(?:\\.[^"\\]*)*)"' # key: "value"
6
- DICT = r'(\w+)\s*:\s*{(.*?)}' # key: {...}
7
- LIST = r'(\w+)\s*:\s*\[([^\[\]]*(?:\[.*?\])*)\]' # key: [value]
8
- FIND = r'\{.*?\}|\[.*?\]' # {} or []
9
4
  # http(s)://user:pass@host:port
10
5
  PROXY = r'^(?:(?P<scheme>https?:\/\/))?(?:(?P<username>[^:@]+):(?P<password>[^@]+)@)?(?P<host>[^:\/]+)(?::(?P<port>\d+))?$'
11
6
 
@@ -1,5 +1,4 @@
1
1
  from .api import PyaterochkaAPI
2
- from enum import Enum
3
2
  import re
4
3
  import json
5
4
  from io import BytesIO
@@ -263,17 +262,3 @@ class Pyaterochka:
263
262
  image.name = f'{url.split("/")[-1]}.{response_type.split("/")[-1]}'
264
263
 
265
264
  return image
266
-
267
- @beartype
268
- async def get_config(self) -> dict:
269
- """
270
- Asynchronously retrieves the configuration from the hardcoded JavaScript file.
271
-
272
- Args:
273
- debug (bool, optional): Whether to print debug information. Defaults to False.
274
-
275
- Returns:
276
- dict: A dictionary representing the configuration if the request is successful, error otherwise.
277
- """
278
-
279
- return await self.api.download_config(config_url=self.HARDCODE_JS_CONFIG)
pyaterochka_api/tools.py CHANGED
@@ -1,8 +1,10 @@
1
1
  from .enums import Patterns
2
2
  import os
3
3
  import re
4
- from tqdm import tqdm
4
+ from beartype import beartype
5
+ import logging
5
6
 
7
+ @beartype
6
8
  def get_env_proxy() -> str | None:
7
9
  """
8
10
  Получает прокси из переменных окружения.
@@ -11,7 +13,8 @@ def get_env_proxy() -> str | None:
11
13
  proxy = os.environ.get("HTTPS_PROXY") or os.environ.get("https_proxy") or os.environ.get("HTTP_PROXY") or os.environ.get("http_proxy")
12
14
  return proxy if proxy else None
13
15
 
14
- def parse_proxy(proxy_str: str | None, trust_env: bool, logger) -> dict | None:
16
+ @beartype
17
+ def parse_proxy(proxy_str: str | None, trust_env: bool, logger: logging.Logger) -> dict | None:
15
18
  logger.debug(f"Parsing proxy string: {proxy_str}")
16
19
 
17
20
  if not proxy_str:
@@ -53,69 +56,3 @@ def parse_proxy(proxy_str: str | None, trust_env: bool, logger) -> dict | None:
53
56
 
54
57
  logger.info(f"Proxy parsed as regex")
55
58
  return proxy_dict
56
-
57
- async def _parse_match(match: str, progress_bar: tqdm | None = None) -> dict:
58
- result = {}
59
-
60
- if progress_bar:
61
- progress_bar.set_description("Parsing strings")
62
-
63
- # Парсинг строк
64
- string_matches = re.finditer(Patterns.STR.value, match)
65
- for m in string_matches:
66
- key, value = m.group(1), m.group(2)
67
- result[key] = value.replace('\"', '"').replace('\\', '\\')
68
-
69
- if progress_bar:
70
- progress_bar.update(1)
71
- progress_bar.set_description("Parsing dictionaries")
72
-
73
- # Парсинг словарей
74
- dict_matches = re.finditer(Patterns.DICT.value, match)
75
- for m in dict_matches:
76
- key, value = m.group(1), m.group(2)
77
- if not re.search(Patterns.STR.value, value):
78
- result[key] = await _parse_match(value, progress_bar)
79
-
80
- if progress_bar:
81
- progress_bar.update(1)
82
- progress_bar.set_description("Parsing lists")
83
-
84
- # Парсинг списков
85
- list_matches = re.finditer(Patterns.LIST.value, match)
86
- for m in list_matches:
87
- key, value = m.group(1), m.group(2)
88
- if not re.search(Patterns.STR.value, value):
89
- result[key] = [await _parse_match(item.group(0), progress_bar) for item in re.finditer(Patterns.FIND.value, value)]
90
-
91
- if progress_bar:
92
- progress_bar.update(1)
93
-
94
- return result
95
-
96
- async def parse_js(js_code: str, debug: bool, logger) -> dict | None:
97
- """
98
- Парсит JavaScript-код и извлекает данные из переменной "n".
99
-
100
- :param js_code: JS-код в виде строки.
101
- :return: Распарсенные данные в виде словаря или None.
102
- """
103
- matches = re.finditer(Patterns.JS.value, js_code)
104
- match_list = list(matches)
105
-
106
- logger.debug(f'Found matches {len(match_list)}')
107
-
108
- progress_bar = tqdm(total=33, desc="Parsing JS", position=0) if debug else None
109
-
110
- if match_list and len(match_list) >= 1:
111
- logger.info('Starting to parse match')
112
- result = await _parse_match(match_list[1].group(0), progress_bar)
113
-
114
- if progress_bar:
115
- progress_bar.close()
116
- logger.info('Complited parsing match')
117
- return result
118
- else:
119
- if progress_bar:
120
- progress_bar.close()
121
- raise Exception("N variable in JS code not found")
@@ -1,15 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyaterochka_api
3
- Version: 0.1.9.1
3
+ Version: 0.2.0
4
4
  Summary: A Python API client for Pyaterochka store catalog
5
- Home-page: https://github.com/Open-Inflation/pyaterochka_api
6
5
  Author: Miskler
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Open-Inflation/pyaterochka_api
8
+ Project-URL: Repository, https://github.com/Open-Inflation/pyaterochka_api
9
+ Project-URL: Documentation, https://open-inflation.github.io/pyaterochka_api/
10
+ Keywords: api,pyaterochka,store,catalog
7
11
  Classifier: Programming Language :: Python :: 3
8
12
  Classifier: Programming Language :: Python :: 3.10
9
13
  Classifier: Programming Language :: Python :: 3.11
10
14
  Classifier: Programming Language :: Python :: 3.12
11
15
  Classifier: Programming Language :: Python :: 3.13
12
- Classifier: License :: OSI Approved :: MIT License
13
16
  Classifier: Operating System :: Microsoft :: Windows
14
17
  Classifier: Operating System :: POSIX :: Linux
15
18
  Classifier: Intended Audience :: Developers
@@ -24,21 +27,11 @@ Requires-Dist: aiohttp
24
27
  Requires-Dist: camoufox[geoip]
25
28
  Requires-Dist: beartype
26
29
  Requires-Dist: fake-useragent
27
- Requires-Dist: tqdm
28
30
  Provides-Extra: tests
29
31
  Requires-Dist: pytest; extra == "tests"
30
32
  Requires-Dist: pytest-asyncio; extra == "tests"
31
33
  Requires-Dist: pytest-typed-schema-shot; extra == "tests"
32
- Dynamic: author
33
- Dynamic: classifier
34
- Dynamic: description
35
- Dynamic: description-content-type
36
- Dynamic: home-page
37
34
  Dynamic: license-file
38
- Dynamic: provides-extra
39
- Dynamic: requires-dist
40
- Dynamic: requires-python
41
- Dynamic: summary
42
35
 
43
36
  # Pyaterochka API *(not official / не официальный)*
44
37
 
@@ -116,10 +109,6 @@ async def main():
116
109
  news = await API.get_news(limit=5)
117
110
  print(f"News output: {news!s:.100s}...\n")
118
111
 
119
- # RUS: Выводит основной конфиг сайта (очень долгая функция, рекомендую сохранять в файл и переиспользовать)
120
- # ENG: Outputs the main config of the site (large function, recommend to save in a file and re-use it)
121
- print(f"Main config: {await API.get_config()!s:.100s}...\n")
122
-
123
112
  # RUS: Если требуется, можно настроить вывод логов в консоль
124
113
  # ENG: If required, you can configure the output of logs in the console
125
114
  API.debug = True
@@ -0,0 +1,10 @@
1
+ pyaterochka_api/__init__.py,sha256=-rsfMGZCT77fmjEHQi4cyyErAZrsQQdbuaqlbOt-a08,130
2
+ pyaterochka_api/api.py,sha256=EsMsyNaFEWCif3iRK6GJCT1o4QHDY72rBgjfeu1BTSU,7204
3
+ pyaterochka_api/enums.py,sha256=H864-J-1VWiEsRxNaGLAkcH2kq92FEj7fhuxwqfRVaw,285
4
+ pyaterochka_api/manager.py,sha256=Wuugv3VuYOInyCBMfGyCCEn6lf4zdr3LwwZk1iT4R44,10261
5
+ pyaterochka_api/tools.py,sha256=fxBa-FKJfbKmup2ZrDTF1u3qyawiHODjG9ofq5ZCG0w,2178
6
+ pyaterochka_api-0.2.0.dist-info/licenses/LICENSE,sha256=Ee_P5XQUYoJuffzRL24j4GWpqgoWphUOKswpB2f9HcQ,1071
7
+ pyaterochka_api-0.2.0.dist-info/METADATA,sha256=7-bQZJW9MFgReD8e2hX1x0p3nVN2YcGixP7PrrpZUQc,9432
8
+ pyaterochka_api-0.2.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
9
+ pyaterochka_api-0.2.0.dist-info/top_level.txt,sha256=NTJa4yZBzfmC9B5FQuFETD9ngGd_KYZ3Hjfw_33aDTE,16
10
+ pyaterochka_api-0.2.0.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- pyaterochka_api/__init__.py,sha256=6XnalFPUumYqDJFyXw2puejJ612o-D1tYjZ_IjQ7Hx0,108
2
- pyaterochka_api/api.py,sha256=KEr28n1aH69cVo0ztHCgB4ANVVZ-CezLWYTiPpfAmoc,7793
3
- pyaterochka_api/enums.py,sha256=JnX4JiHzXyRo4se8sCFx0LyqcKlXXED0VcA0xI7r_ZI,621
4
- pyaterochka_api/manager.py,sha256=yQw0njGCsropysT-_siuyNxXNpX-VJKOcVD8b-aV48I,10765
5
- pyaterochka_api/tools.py,sha256=xFOThNRClX4u0cMfmQ5fVQKLM2Fn-rBAekzo_yBvRnQ,4447
6
- pyaterochka_api-0.1.9.1.dist-info/licenses/LICENSE,sha256=Ee_P5XQUYoJuffzRL24j4GWpqgoWphUOKswpB2f9HcQ,1071
7
- pyaterochka_api-0.1.9.1.dist-info/METADATA,sha256=ZQOhWOFzmF9nr2LfutfAVfgkzorB_OYb4sJmtpHtruI,9857
8
- pyaterochka_api-0.1.9.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
9
- pyaterochka_api-0.1.9.1.dist-info/top_level.txt,sha256=NTJa4yZBzfmC9B5FQuFETD9ngGd_KYZ3Hjfw_33aDTE,16
10
- pyaterochka_api-0.1.9.1.dist-info/RECORD,,