Skip to content

Commit da676e4

Browse files
authored
Merge pull request #5 from Open-Inflation/codex/auto-generate-documentation-with-mkdocs
Simplify docs generation
2 parents 7000343 + b12d9cc commit da676e4

65 files changed

Lines changed: 886 additions & 541 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,10 @@ venv.bak/
145145
# Rope project settings
146146
.ropeproject
147147

148-
# mkdocs documentation
149-
/site
148+
# documentation build
149+
docs/_build/
150+
docs/source/_build/
151+
docs_src/reference/
150152

151153
# mypy
152154
.mypy_cache/

README.md

Lines changed: 30 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -14,167 +14,45 @@ Perekrestok (Перекрёсток) - https://www.perekrestok.ru/
1414
### Принцип работы
1515

1616
> Библиотека полностью повторяет сетевую работу обычного пользователя на сайте.
17-
Основная логика сетевых запросов заложена в `api.py`, она управляется `PerekrestokAPI()` в `manager.py`.
18-
Существует вспомогательный модуль `abstraction.py` хранящий в себе статичные классы, которых принимаю в аргументах некоторые методы в `PerekrestokAPI()`.
19-
2017
2118

2219
# Usage / Использование
23-
### Базовая структура
24-
```py
25-
import asyncio
26-
from perekrestok_api import PerekrestokAPI, ABSTRACT
2720

28-
async def main():
29-
...
21+
```py
22+
from perekrestok_api import PerekrestokAPI
23+
from perekrestok_api import abstraction
24+
25+
26+
def main():
27+
with PerekrestokAPI() as Api:
28+
geopos_handler = Api.Geolocation.current()
29+
geopos = geopos_handler.json()
30+
print(f'Текущий город сессии {geopos["content"]["city"]["name"]} ({geopos["content"]["city"]["id"]})')
31+
32+
# Получаем список категорий
33+
categories = Api.Catalog.tree()
34+
cat = categories.json()
35+
print(f'Список категорий: {len(cat["content"]["items"])}')
36+
37+
# Выводим первую категорию
38+
print(f'Категория: {cat["content"]["items"][0]["category"]["title"]} ({cat["content"]["items"][0]["category"]["id"]})')
39+
# Получаем список товаров
40+
filter = abstraction.CatalogFeedFilter()
41+
filter.CATEGORY_ID = cat["content"]["items"][0]["category"]["id"]
42+
products = Api.Catalog.feed(filter=filter)
43+
prod = products.json()
44+
45+
# Выводим первый товар
46+
print(f'Первый товар: {prod["content"]["items"][0]["title"]} ({prod["content"]["items"][0]["id"]})')
3047

3148
if __name__ == "__main__":
32-
asyncio.run(main())
33-
```
34-
35-
---
36-
37-
### Работа с геолокацией в сессии:
38-
*От геолокации и способа получения (доставка/забрать из магазина) зависит выдача каталога!*
39-
```py
40-
async with PerekrestokAPI(
41-
debug = False, # Включить ли логирование библиотеки
42-
token_retry_attempts = 3 # Количество попыток авторизации
43-
) as Api:
44-
geopos_handler = await Api.Geolocation.current()
45-
geopos = geopos_handler.response
46-
print(f'Текущий город сессии {geopos["content"]["city"]["name"]} ({geopos["content"]["city"]["id"]})')
47-
48-
# Ищем геолокацию города по названию
49-
content_handler = await Api.Geolocation.search("нижневартовск")
50-
content = content_handler.response
51-
52-
# Ищем магазины в этом городе
53-
point_in_city_handler = await Api.Geolocation.Shop.on_map(
54-
# Мы можем выбрать магазины на карте через геопозицию
55-
position=ABSTRACT.Geoposition(content['content']['items'][0]['location']['coordinates']),
56-
# Или через ID населенного пункта (особой разницы нет). Эти параметры не противоречат друг другу.
57-
city_id=content['content']['items'][0]['id'],
58-
59-
# Количество магазинов в ответе
60-
limit=3,
61-
62-
# Фильтр особенностей магазина, `4` - это кофепоинт
63-
# С актуальным списком "особенностей" для магазинов можно ознакомиться в `await Api.Geolocation.Shop.features()`
64-
features=[4],
65-
66-
# Сортировка как "самый ближайший"
67-
sort=ABSTRACT.GeologicationPointSort.Distance.ASC
68-
)
69-
point_in_city = point_in_city_handler.response
70-
71-
# Выбираем первый (по сути центральный, т.к. сортировка по удалению от конкретной точки)
72-
shop_handler = await Api.Geolocation.Selection.shop(point_in_city['content']['items'][0]['id'])
73-
shop = shop_handler.response
74-
print(f'Выбран магазин \"{shop["content"]["shop"]["title"]}\", по адресу {shop["content"]["shop"]["address"]}')
75-
76-
# Теперь можем проверить, действительно ли сменили геолокацию
77-
geopos_handler = await Api.Geolocation.current()
78-
geopos = geopos_handler.response
79-
80-
print(f'Текущий город сессии {geopos["content"]["city"]["name"]} ({geopos["content"]["city"]["id"]})')
49+
main()
8150
```
8251
```bash
8352
> Текущий город сессии Москва (81)
84-
> Выбран магазин "ТЦ Green Park", по адресу Ханты-Мансийский Автономный округ - Югра, г Нижневартовск, ул Ленина, зд 8
85-
> Текущий город сессии Нижневартовск (73)
86-
```
87-
88-
---
89-
90-
### Взаимодействие с каталогом
91-
92-
```py
93-
async with PerekrestokAPI() as Api:
94-
# Получение дерева категорий каталога
95-
tree_handler = await Api.Catalog.tree()
96-
tree = tree_handler.response
97-
98-
# Список для хранения всех обработанных товаров
99-
products = []
100-
101-
# Прогресс-бар для отображения процесса обработки
102-
tq = tqdm.tqdm(tree["content"]["items"], desc='Обработано категорий')
103-
104-
# Рекурсивная функция для обработки категорий и их подкатегорий
105-
async def process_sub(tree_items, depth=0):
106-
# Используем прогресс-бар только на верхнем уровне вложенности
107-
current_level = tq if depth == 0 else tree_items
108-
109-
for category_group in current_level:
110-
category = category_group["category"]
111-
112-
# Формирование фильтра для запроса каталога
113-
feed_filter = ABSTRACT.CatalogFeedFilter()
114-
feed_filter.CATEGORY_ID = category["id"]
115-
116-
# Запрашиваем товары из текущей категории
117-
catalog_handler = await Api.Catalog.feed(filter=feed_filter)
118-
catalog = catalog_handler.response
119-
page = 1
120-
121-
# Цикл обработки всех страниц товаров в категории
122-
while page > 0 and len(catalog["content"]["items"]) > 0:
123-
for product in catalog["content"]["items"]:
124-
# Сохраняем название и ID товара
125-
products.append(f'{product["title"]} ({product["id"]})')
126-
tq.desc = f'Обработано карточек: {len(products)}'
127-
128-
# Переход к следующей странице или завершение обработки
129-
if catalog['content']['paginator']['nextPageExists']:
130-
page += 1
131-
catalog_handler = await Api.Catalog.feed(filter=feed_filter, page=page)
132-
catalog = catalog_handler.response
133-
else:
134-
page = -1
135-
136-
# Рекурсивно обрабатываем подкатегории
137-
for child in category_group.get("children", []):
138-
await process_sub([child], depth + 1)
139-
140-
# Запуск обработки дерева категорий
141-
await process_sub(tree["content"]["items"])
142-
143-
# Вывод итоговой статистики
144-
print(f'Общее количество встреченных карточек: {len(products)}')
145-
print(f'Уникальных товаров: {len(set(products))}')
146-
print(f'Среднее количество повторений карточки: {round(len(products) / len(set(products)), 2)}')
147-
```
148-
```bash
149-
> Обработано карточек: 41620: 100%|█████████████████████████| 29/29 [03:56<00:00, 8.15s/it]
150-
> Общее количество встреченных карточек: 41620
151-
> Уникальных товаров: 17630
152-
> Среднее количество повторений карточки: 2.36
153-
```
154-
155-
---
156-
157-
### Загрузка изображений
158-
```py
159-
async with PerekrestokAPI() as Api:
160-
img = await Api.General.download_image("https://cdn-img.perekrestok.ru/i/400x400-fit/xdelivery/files/ae/2a/4f39b2a249768b268ed9f325c155.png")
161-
162-
with open(img.name, "wb") as f:
163-
f.write(img.read())
164-
```
165-
166-
### Или параллельная загрузка
167-
```py
168-
async with PerekrestokAPI() as Api:
169-
tasks = [
170-
Api.General.download_image("https://cdn-img.perekrestok.ru/i/400x400-fit/xdelivery/files/ae/2a/4f39b2a249768b268ed9f325c155.png"),
171-
Api.General.download_image("https://cdn-img.perekrestok.ru/i/400x400-fit/xdelivery/files/ae/2a/4f39b2a249768b268ed9f325c155.png")
172-
]
173-
174-
results = await asyncio.gather(*tasks)
175-
for result in results:
176-
with open(result.name, "wb") as f:
177-
f.write(result.read())
53+
> Список категорий: 31
54+
> Категория: Летний сезон (1585)
55+
> Первый товар: Пиво Василеостровское Тройной пшеничный эль нефильтрованное 6.9%, 750мл (66750)
17856
```
17957

18058
---

docs/source/Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = .
9+
BUILDDIR = _build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
perekrestok\_api.abstraction
2+
============================
3+
4+
.. automodule:: perekrestok_api.abstraction
5+
6+
7+
.. rubric:: Classes
8+
9+
.. autosummary::
10+
11+
Any
12+
BannerPlace
13+
CatalogFeedFilter
14+
CatalogFeedSort
15+
GeolocationPointSort
16+
Geoposition
17+
QualifierFeatureKey
18+
SortOption
19+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
perekrestok\_api.endpoints.advertising
2+
======================================
3+
4+
.. automodule:: perekrestok_api.endpoints.advertising
5+
6+
7+
.. rubric:: Classes
8+
9+
.. autosummary::
10+
11+
ClassAdvertising
12+
Response
13+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
perekrestok\_api.endpoints.catalog
2+
==================================
3+
4+
.. automodule:: perekrestok_api.endpoints.catalog
5+
6+
7+
.. rubric:: Classes
8+
9+
.. autosummary::
10+
11+
ClassCatalog
12+
ProductService
13+
Response
14+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
perekrestok\_api.endpoints.general
2+
==================================
3+
4+
.. automodule:: perekrestok_api.endpoints.general
5+
6+
7+
.. rubric:: Classes
8+
9+
.. autosummary::
10+
11+
ClassGeneral
12+
Response
13+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
perekrestok\_api.endpoints.geolocation
2+
======================================
3+
4+
.. automodule:: perekrestok_api.endpoints.geolocation
5+
6+
7+
.. rubric:: Classes
8+
9+
.. autosummary::
10+
11+
ClassGeolocation
12+
GeolocationSelection
13+
Response
14+
ShopService
15+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
perekrestok\_api.endpoints
2+
==========================
3+
4+
.. automodule:: perekrestok_api.endpoints
5+
6+
7+
.. rubric:: Modules
8+
9+
.. autosummary::
10+
:toctree:
11+
:recursive:
12+
13+
advertising
14+
catalog
15+
general
16+
geolocation

docs/source/api.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
API Reference
2+
=============
3+
4+
.. autosummary::
5+
:recursive:
6+
:toctree: _api
7+
8+
perekrestok_api.endpoints
9+
perekrestok_api.abstraction

0 commit comments

Comments
 (0)