Skip to content

Commit

Permalink
Merge pull request #43 from megahomyak/master
Browse files Browse the repository at this point in the history
Re-request on httpx.ReadTimeout
  • Loading branch information
nm17 committed Feb 8, 2022
2 parents 54e60a2 + 509f02c commit 0b6a931
Show file tree
Hide file tree
Showing 15 changed files with 268 additions and 41 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,6 @@ pip-selfcheck.json
*.code-workspace

# End of https://www.toptal.com/developers/gitignore/api/linux,python,virtualenv,pycharm+all,vscode


examples/config/config.json
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ NetSchoolAPI — это асинхронный клиент для «Сетев
[Документация](https://netschoolapi.readthedocs.io/ru/latest/)

А ещё у нас есть примеры в `/examples`.

## Жалобы и предложения

Обсуждение библиотеки ведётся в [чате](https://t.me/netschoolapi/) проекта в телеграме.
Expand Down
6 changes: 5 additions & 1 deletion docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

* `assignment: Assignment` --- урок, у которого нужно получить прикреплённые файлы

Возвращает список объектов [`Attachment`](reference.md#attachment) или пустой список, если к уроку не прикреплено файлов. Скачать вложение из файла можно с помощью `netschoolapi_client.download_attachment()` или `netschoolapi_client.download_attachment_as_bytes()`.
Возвращает список объектов [`Attachment`](reference.md#attachment) или пустой список, если к уроку не прикреплено файлов.

## Объявления {#announcements}

Expand All @@ -35,3 +35,7 @@
## Информация о школе {#school}

`.school()` --- возвращает [информацию](reference.md#school) о школе.

## Скачивание файлов из вложений {#downloading_files_from_attachments}

Скачать файл из вложения можно с помощью `netschoolapi_client.download_attachment()` или `netschoolapi_client.download_attachment_as_bytes()`.
21 changes: 21 additions & 0 deletions examples/announcements_and_their_attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import PIL.Image

import netschoolapi
from examples.preparation.preparation import run_main
from examples.preparation.utils import pprint


async def main(client: netschoolapi.NetSchoolAPI):
print("Announcements:")
announcements = await client.announcements()
pprint(announcements)
print()
print("Now showing all images found in announcements.")
for announcement in announcements:
for attachment in announcement.attachments:
if attachment.name.endswith((".png", ".jpg", ".jpeg")):
image = await client.download_attachment_as_bytes(attachment)
PIL.Image.open(image).show()


run_main(main)
20 changes: 20 additions & 0 deletions examples/config/config_maker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import json
from dataclasses import dataclass


@dataclass
class Config:
url: str
user_name: str
password: str
school: str


def make_config():
try:
return Config(**json.load(open("config/config.json", encoding="utf-8")))
except FileNotFoundError:
raise FileNotFoundError(
"Please create a config/config.json file (use "
"config/config_template.json as a template)"
)
6 changes: 6 additions & 0 deletions examples/config/config_template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"url": "https://edu.admoblkaluga.ru:444/",
"user_name": "Аркадий Степанович Петроненко",
"password": "||4R0Ль_йцУk3H",
"school": "МБОУ \"СОШ \"Технический лицей\""
}
23 changes: 23 additions & 0 deletions examples/diary_and_its_attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import netschoolapi
from examples.preparation import utils
from preparation.preparation import run_main


async def main(client: netschoolapi.NetSchoolAPI):
print("Diary:")
diary = await client.diary()
utils.pprint(diary)
for day in diary.schedule:
for lesson in day.lessons:
for assignment in lesson.assignments:
attachments = await client.attachments(assignment)
if attachments:
print(
f"Some attachments found on day {day.day} on "
f"{lesson.subject} homework: {attachments}"
)
# You can also download them using
# .download_attachment() or .download_attachment_as_bytes()


run_main(main)
11 changes: 11 additions & 0 deletions examples/overdue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import netschoolapi
from examples.preparation.preparation import run_main
from examples.preparation.utils import pprint


async def main(client: netschoolapi.NetSchoolAPI):
print("Overdue:")
pprint(await client.overdue())


run_main(main)
28 changes: 28 additions & 0 deletions examples/preparation/preparation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import asyncio
from typing import Callable, Awaitable

# noinspection PyUnresolvedReferences
# because working path from an IDE project not always equals to a working path
# when launching the script (so if I launch something from examples, my working
# directory will be "examples", but my IDE thinks that it is "examples/.."
# (project root))
from config.config_maker import Config, make_config

import netschoolapi


async def login(config: Config) -> netschoolapi.NetSchoolAPI:
client = netschoolapi.NetSchoolAPI(config.url)
await client.login(config.user_name, config.password, config.school)
return client


async def _run_main(main):
config = make_config()
client = await login(config)
async with client:
await main(client)


def run_main(main: Callable[[netschoolapi.NetSchoolAPI], Awaitable]):
asyncio.get_event_loop().run_until_complete(_run_main(main))
7 changes: 7 additions & 0 deletions examples/preparation/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import rich.console

console = rich.console.Console(no_color=True, width=80)


def pprint(object_):
console.print(object_)
11 changes: 11 additions & 0 deletions examples/school.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import netschoolapi
from examples.preparation.preparation import run_main
from examples.preparation.utils import pprint


async def main(client: netschoolapi.NetSchoolAPI):
print("School info:")
pprint(await client.school())


run_main(main)
55 changes: 55 additions & 0 deletions netschoolapi/async_client_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import asyncio
import functools
from typing import Optional, Awaitable, Protocol

import httpx

from netschoolapi import errors

DEFAULT_REQUESTS_TIMEOUT = 5


class Requester(Protocol):

def __call__(
self, path: str, method="GET", params: dict = None,
json: dict = None, data: dict = None) -> Awaitable:
pass


class AsyncClientWrapper:
def __init__(
self, async_client: httpx.AsyncClient,
default_requests_timeout: int = None):
self.client = async_client
self._default_requests_timeout = (
default_requests_timeout or DEFAULT_REQUESTS_TIMEOUT
)

def make_requester(self, requests_timeout: Optional[int]) -> Requester:
# noinspection PyTypeChecker
return functools.partial(self.request, requests_timeout)

async def request(
self, requests_timeout: Optional[int], path: str,
method="GET", params: dict = None, json: dict = None,
data: dict = None):
try:
return await asyncio.wait_for(self._infinite_request(
path, method, params, json, data,
), requests_timeout or self._default_requests_timeout)
except asyncio.TimeoutError:
raise errors.NoResponseFromServer from None

async def _infinite_request(
self, path: str, method: str, params: Optional[dict],
json: Optional[dict], data: Optional[dict]):
while True:
try:
response = await self.client.request(
method, path, params=params, json=json, data=data
)
except httpx.ReadTimeout:
pass
else:
return response
4 changes: 4 additions & 0 deletions netschoolapi/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ class AuthError(NetSchoolAPIError):

class SchoolNotFoundError(NetSchoolAPIError):
pass


class NoResponseFromServer(NetSchoolAPIError):
pass
Loading

0 comments on commit 0b6a931

Please sign in to comment.