Skip to content

Commit

Permalink
Reduced the potentially errorneous repetition
Browse files Browse the repository at this point in the history
  • Loading branch information
megahomyak committed Nov 25, 2022
1 parent 9665c55 commit 5fb580f
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 71 deletions.
23 changes: 7 additions & 16 deletions netschoolapi/async_client_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@

class Requester(Protocol):

def __call__(
self, path: str, method="GET", params: dict = None,
json: dict = None, data: dict = None) -> Awaitable:
def __call__(self, request: httpx.Request, follow_redirects=False) -> Awaitable:
pass


Expand All @@ -31,33 +29,26 @@ def make_requester(self, requests_timeout: Optional[int]) -> Requester:
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, allow_redirects=False):
self, requests_timeout: Optional[int], request: httpx.Request,
follow_redirects=False):
if requests_timeout is None:
requests_timeout = self._default_requests_timeout
try:
if requests_timeout == 0:
return await self._infinite_request(
path, method, params, json, data, allow_redirects
request, follow_redirects
)
else:
return await asyncio.wait_for(self._infinite_request(
path, method, params, json, data, allow_redirects
request, follow_redirects
), 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],
allow_redirects: bool):
async def _infinite_request(self, request: httpx.Request, follow_redirects: bool):
while True:
try:
response = await self.client.request(
method, path, params=params, json=json, data=data, # type: ignore
follow_redirects=allow_redirects # type: ignore
)
response = await self.client.send(request, follow_redirects=follow_redirects)
except httpx.ReadTimeout:
pass
else:
Expand Down
146 changes: 91 additions & 55 deletions netschoolapi/netschoolapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ async def _die_on_bad_status(response: Response):


class NetSchoolAPI:
def __init__(
self, url: str, default_requests_timeout: int = None):
def __init__(self, url: str, default_requests_timeout: int = None):
url = url.rstrip('/')
self._wrapped_client = AsyncClientWrapper(
async_client=AsyncClient(
Expand Down Expand Up @@ -51,10 +50,14 @@ async def login(
requests_timeout: int = None):
requester = self._wrapped_client.make_requester(requests_timeout)
# Getting the `NSSESSIONID` cookie for `auth/getdata`
await requester('logindata')
await requester(self._wrapped_client.client.build_request(
method="GET", url="logindata"
))

# Getting the `NSSESSIONID` cookie for `login`
response = await requester('auth/getdata', method="POST")
response = await requester(self._wrapped_client.client.build_request(
method="POST", url='auth/getdata'
))
login_meta = response.json()
salt = login_meta.pop('salt')

Expand All @@ -66,16 +69,18 @@ async def login(

try:
response = await requester(
'login',
data={
'loginType': 1,
**(await self._address(school_name_or_id, requester)),
'un': user_name,
'pw': pw,
'pw2': pw2,
**login_meta,
},
method="POST"
self._wrapped_client.client.build_request(
method="POST",
url='login',
data={
'loginType': 1,
**(await self._address(school_name_or_id, requester)),
'un': user_name,
'pw': pw,
'pw2': pw2,
**login_meta,
},
)
)
except httpx.HTTPStatusError as http_status_error:
if http_status_error.response.status_code == httpx.codes.CONFLICT:
Expand All @@ -99,18 +104,22 @@ async def login(
self._access_token = auth_result["at"]
self._wrapped_client.client.headers['at'] = auth_result['at']

response = await requester('student/diary/init')
response = await requester(self._wrapped_client.client.build_request(
method="GET", url='student/diary/init',
))
diary_info = response.json()
student = diary_info['students'][diary_info['currentStudentId']]
self._student_id = student['studentId']

response = await requester('years/current')
response = await requester(self._wrapped_client.client.build_request(
method="GET", url='years/current'
))
year_reference = response.json()
self._year_id = year_reference['id']

response = await requester(
'grade/assignment/types', params={'all': False}
)
response = await requester(self._wrapped_client.client.build_request(
method="GET", url="grade/assignment/types", params={"all": False},
))
assignment_reference = response.json()
self._assignment_types = {
assignment['id']: assignment['name']
Expand All @@ -119,13 +128,11 @@ async def login(
self._login_data = (user_name, password, school_name_or_id)

async def _request_with_optional_relogin(
self, requests_timeout: Optional[int], path: str,
method="GET", params: dict = None, json: dict = None,
data: dict = None, allow_redirects=False):
self, requests_timeout: Optional[int], request: httpx.Request,
follow_redirects=False):
try:
response = await self._wrapped_client.request(
requests_timeout, path, method, params, json,
data, allow_redirects
requests_timeout, request
)
except httpx.HTTPStatusError as http_status_error:
if (
Expand All @@ -135,8 +142,7 @@ async def _request_with_optional_relogin(
if self._login_data:
await self.login(*self._login_data)
return await self._request_with_optional_relogin(
requests_timeout, path, method, params, json,
data, allow_redirects
requests_timeout, request, follow_redirects
)
else:
raise errors.AuthError(
Expand All @@ -154,7 +160,9 @@ async def download_attachment(
buffer.write((
await self._request_with_optional_relogin(
requests_timeout,
f"attachments/{attachment_id}",
self._wrapped_client.client.build_request(
method="GET", url=f"attachments/{attachment_id}",
)
)
).content)

Expand All @@ -172,13 +180,16 @@ async def diary(

response = await self._request_with_optional_relogin(
requests_timeout,
'student/diary',
params={
'studentId': self._student_id,
'yearId': self._year_id,
'weekStart': start.isoformat(),
'weekEnd': end.isoformat(),
},
self._wrapped_client.client.build_request(
method="GET",
url="student/diary",
params={
'studentId': self._student_id,
'yearId': self._year_id,
'weekStart': start.isoformat(),
'weekEnd': end.isoformat(),
},
)
)
diary_schema = schemas.Diary()
diary_schema.context['assignment_types'] = self._assignment_types
Expand All @@ -199,13 +210,16 @@ async def overdue(

response = await self._request_with_optional_relogin(
requests_timeout,
'student/diary/pastMandatory',
params={
'studentId': self._student_id,
'yearId': self._year_id,
'weekStart': start.isoformat(),
'weekEnd': end.isoformat(),
},
self._wrapped_client.client.build_request(
method="GET",
url='student/diary/pastMandatory',
params={
'studentId': self._student_id,
'yearId': self._year_id,
'weekStart': start.isoformat(),
'weekEnd': end.isoformat(),
},
)
)
assignments_schema = schemas.Assignment()
assignments_schema.context['assignment_types'] = self._assignment_types
Expand All @@ -217,8 +231,11 @@ async def announcements(
requests_timeout: int = None) -> List[schemas.Announcement]:
response = await self._request_with_optional_relogin(
requests_timeout,
'announcements',
params={'take': take},
self._wrapped_client.client.build_request(
method="GET",
url="announcements",
params={"take": take},
)
)
announcements = schemas.Announcement().load(response.json(), many=True)
return announcements # type: ignore
Expand All @@ -228,10 +245,12 @@ async def attachments(
requests_timeout: int = None) -> List[schemas.Attachment]:
response = await self._request_with_optional_relogin(
requests_timeout,
method="POST",
path='student/diary/get-attachments',
params={'studentId': self._student_id},
json={'assignId': [assignment_id]},
self._wrapped_client.client.build_request(
method="POST",
url='student/diary/get-attachments',
params={'studentId': self._student_id},
json={'assignId': [assignment_id]},
),
)
response = response.json()
if not response:
Expand All @@ -243,7 +262,10 @@ async def attachments(
async def school(self, requests_timeout: int = None) -> schemas.School:
response = await self._request_with_optional_relogin(
requests_timeout,
'schools/{0}/card'.format(self._school_id),
self._wrapped_client.client.build_request(
method="GET",
url='schools/{0}/card'.format(self._school_id),
)
)
school = schemas.School().load(response.json())
return school # type: ignore
Expand All @@ -252,8 +274,10 @@ async def logout(self, requests_timeout: int = None):
try:
await self._wrapped_client.request(
requests_timeout,
'auth/logout',
method="POST",
self._wrapped_client.client.build_request(
method="POST",
url='auth/logout',
)
)
except httpx.HTTPStatusError as http_status_error:
if (
Expand All @@ -273,14 +297,24 @@ async def full_logout(self, requests_timeout: int = None):

async def schools(
self, requests_timeout: int = None) -> List[schemas.ShortSchool]:
resp = await self._wrapped_client.request(requests_timeout, "addresses/schools")
resp = await self._wrapped_client.request(
requests_timeout,
self._wrapped_client.client.build_request(
method="GET", url="addresses/schools",
)
)
schools = schemas.ShortSchool().load(resp.json(), many=True)
return schools # type: ignore

async def _address(
self, school_name_or_id: Union[int, str],
requester: Requester) -> Dict[str, int]:
schools = (await requester("addresses/schools")).json()
schools = (await requester(
self._wrapped_client.client.build_request(
method="GET",
url="addresses/schools",
)
)).json()

for school in schools:
if school["name"] == school_name_or_id or school["id"] == school_name_or_id:
Expand All @@ -301,8 +335,10 @@ async def download_profile_picture(
buffer.write((
await self._request_with_optional_relogin(
requests_timeout,
"users/photo",
params={"at": self._access_token, "userId": user_id},
allow_redirects=True
self._wrapped_client.client.build_request(
method="GET",
url="users/photo",
params={"at": self._access_token, "userId": user_id},
)
)
).content)

0 comments on commit 5fb580f

Please sign in to comment.