Skip to content

Commit add5546

Browse files
committed
a few fixes
1 parent 966dd2b commit add5546

File tree

14 files changed

+133
-91
lines changed

14 files changed

+133
-91
lines changed

scratchattach/cloud/cloud.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from ._base import BaseCloud
66
from typing import Type
7-
from ..utils.requests import Requests as requests
7+
from ..utils.requests import requests
88
from ..utils import exceptions, commons
99
from ..site import cloud_activity
1010

scratchattach/eventhandlers/_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from threading import Thread
66
from collections.abc import Callable
77
import traceback
8-
from ..utils.requests import Requests as requests
8+
from ..utils.requests import requests
99
from ..utils import exceptions
1010

1111
class BaseEventHandler(ABC):

scratchattach/other/other_apis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from ..utils import commons
88
from ..utils.enums import Languages, Language, TTSVoices, TTSVoice
99
from ..utils.exceptions import BadRequest, InvalidLanguage, InvalidTTSGender
10-
from ..utils.requests import Requests as requests
10+
from ..utils.requests import requests
1111
from typing import Optional
1212

1313

scratchattach/other/project_json_capabilities.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from abc import ABC, abstractmethod
1313
from ..utils import exceptions
1414
from ..utils.commons import empty_project_json
15-
from ..utils.requests import Requests as requests
15+
from ..utils.requests import requests
1616
# noinspection PyPep8Naming
1717
def load_components(json_data: list, ComponentClass: type, target_list: list):
1818
for element in json_data:

scratchattach/site/_base.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
from __future__ import annotations
22

33
from abc import ABC, abstractmethod
4+
from types import FunctionType
5+
from typing import TypeVar, Optional
46

57
import requests
8+
from . import session
69
from ..utils import exceptions, commons
7-
from typing import TypeVar
8-
from types import FunctionType
910

1011
C = TypeVar("C", bound="BaseSiteComponent")
1112
class BaseSiteComponent(ABC):
13+
_session: Optional[session.Session]
14+
update_api: str
15+
_headers: dict[str, str]
16+
_cookies: dict[str, str]
1217
@abstractmethod
1318
def __init__(self):
14-
self._session = None
15-
self._cookies = None
16-
self._headers = None
17-
self.update_API = None
19+
pass
1820

1921
def update(self):
2022
"""
2123
Updates the attributes of the object by performing an API response. Returns True if the update was successful.
2224
"""
2325
response = self.update_function(
24-
self.update_API,
26+
self.update_api,
2527
headers=self._headers,
2628
cookies=self._cookies, timeout=10
2729
)
@@ -45,7 +47,6 @@ def _update_from_dict(self, data) -> bool:
4547
"""
4648
Parses the API response that is fetched in the update-method. Class specific, must be overridden in classes inheriting from this one.
4749
"""
48-
pass
4950

5051
def _assert_auth(self):
5152
if self._session is None:

scratchattach/site/backpack_asset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from ._base import BaseSiteComponent
88
from ..utils import exceptions
9-
from ..utils.requests import Requests as requests
9+
from ..utils.requests import requests
1010

1111

1212

scratchattach/site/classroom.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ def __init__(self, **entries):
2424
# NOTE: THIS DOESN'T WORK WITH CLOSED CLASSES!
2525
self.update_function = requests.get
2626
if "id" in entries:
27-
self.update_API = f"https://api.scratch.mit.edu/classrooms/{entries['id']}"
27+
self.update_api = f"https://api.scratch.mit.edu/classrooms/{entries['id']}"
2828
elif "classtoken" in entries:
29-
self.update_API = f"https://api.scratch.mit.edu/classtoken/{entries['classtoken']}"
29+
self.update_api = f"https://api.scratch.mit.edu/classtoken/{entries['classtoken']}"
3030
else:
3131
raise KeyError(f"No class id or token provided! Entries: {entries}")
3232

scratchattach/site/forum.py

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
"""ForumTopic and ForumPost classes"""
22
from __future__ import annotations
33

4+
from dataclasses import dataclass, field
5+
from typing import Optional
6+
from urllib.parse import urlparse, parse_qs
7+
import xml.etree.ElementTree as ET
8+
9+
from bs4 import BeautifulSoup
10+
411
from . import user
12+
from . import session
513
from ..utils.commons import headers
614
from ..utils import exceptions, commons
715
from ._base import BaseSiteComponent
8-
import xml.etree.ElementTree as ET
9-
from bs4 import BeautifulSoup
10-
from urllib.parse import urlparse, parse_qs
11-
12-
from ..utils.requests import Requests as requests
16+
from ..utils.requests import requests
1317

18+
@dataclass
1419
class ForumTopic(BaseSiteComponent):
1520
'''
1621
Represents a Scratch forum topic.
@@ -33,20 +38,18 @@ class ForumTopic(BaseSiteComponent):
3338
3439
:.update(): Updates the attributes
3540
'''
36-
37-
def __init__(self, **entries):
41+
id: int
42+
title: str
43+
category_name: str
44+
last_updated: str
45+
_session: Optional[session.Session] = field(default=None)
46+
reply_count: Optional[int] = field(default=None)
47+
view_count: Optional[int] = field(default=None)
48+
49+
def __post_init__(self):
3850
# Info on how the .update method has to fetch the data:
3951
self.update_function = requests.get
40-
self.update_API = f"https://scratch.mit.edu/discuss/feeds/topic/{entries['id']}/"
41-
42-
# Set attributes every Project object needs to have:
43-
self._session = None
44-
self.id = 0
45-
self.reply_count = None
46-
self.view_count = None
47-
48-
# Update attributes from entries dict:
49-
self.__dict__.update(entries)
52+
self.update_api = f"https://scratch.mit.edu/discuss/feeds/topic/{self.id}/"
5053

5154
# Headers and cookies:
5255
if self._session is None:
@@ -65,7 +68,7 @@ def update(self):
6568
# As there is no JSON API for getting forum topics anymore,
6669
# the data has to be retrieved from the XML feed.
6770
response = self.update_function(
68-
self.update_API,
71+
self.update_api,
6972
headers = self._headers,
7073
cookies = self._cookies, timeout=20 # fetching forums can take very long
7174
)
@@ -87,15 +90,20 @@ def update(self):
8790
raise exceptions.ScrapeError(str(e))
8891
else:
8992
raise exceptions.ForumContentNotFound
90-
91-
return self._update_from_dict(dict(
92-
title = title, category_name = category_name, last_updated = last_updated
93-
))
94-
95-
96-
def _update_from_dict(self, data):
97-
self.__dict__.update(data)
93+
self.title = title
94+
self.category_name = category_name
95+
self.last_updated = last_updated
9896
return True
97+
98+
@classmethod
99+
def from_id(cls, id: int, session: session.Session, update: bool = False):
100+
new = cls(id=id, _session=session, title="", last_updated="", category_name="")
101+
if update:
102+
new.update()
103+
return new
104+
105+
def _update_from_dict(self, data):
106+
raise NotImplementedError()
99107

100108
def posts(self, *, page=1, order="oldest"):
101109
"""
@@ -157,7 +165,6 @@ def first_post(self):
157165
if len(posts) > 0:
158166
return posts[0]
159167

160-
161168
class ForumPost(BaseSiteComponent):
162169
'''
163170
Represents a Scratch forum post.
@@ -195,7 +202,7 @@ def __init__(self, **entries):
195202

196203
# A forum post can't be updated the usual way as there is no API anymore
197204
self.update_function = None
198-
self.update_API = None
205+
self.update_api = None
199206

200207
# Set attributes every Project object needs to have:
201208
self._session = None
@@ -225,14 +232,14 @@ def update(self):
225232
As there is no API for retrieving a single post anymore, this requires reloading the forum page.
226233
"""
227234
page = 1
228-
posts = ForumTopic(id=self.topic_id, _session=self._session).posts(page=1)
235+
posts = ForumTopic.from_id(id=self.topic_id, session=self._session).posts(page=1)
229236
while posts != []:
230237
matching = list(filter(lambda x : int(x.id) == int(self.id), posts))
231238
if len(matching) > 0:
232239
this = matching[0]
233240
break
234241
page += 1
235-
posts = ForumTopic(id=self.topic_id, _session=self._session).posts(page=page)
242+
posts = ForumTopic.from_id(id=self.topic_id, session=self._session).posts(page=page)
236243
else:
237244
return False
238245

scratchattach/site/project.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from ..utils.commons import empty_project_json, headers
1313
from ._base import BaseSiteComponent
1414
from ..other.project_json_capabilities import ProjectBody
15-
from ..utils.requests import Requests as requests
15+
from ..utils.requests import requests
1616

1717
CREATE_PROJECT_USES: list[float] = []
1818

@@ -28,7 +28,7 @@ def __init__(self, **entries):
2828

2929
# Info on how the .update method has to fetch the data:
3030
self.update_function = requests.get
31-
self.update_API = f"https://api.scratch.mit.edu/projects/{entries['id']}"
31+
self.update_api = f"https://api.scratch.mit.edu/projects/{entries['id']}"
3232

3333
# Set attributes every Project object needs to have:
3434
self._session = None

scratchattach/site/session.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import re
1111
import time
1212
import warnings
13-
from typing import Optional, TypeVar, TYPE_CHECKING, overload, Any
13+
from typing import Optional, TypeVar, TYPE_CHECKING, overload, Any, Union
1414
from contextlib import contextmanager
1515
from threading import local
1616

@@ -38,7 +38,7 @@
3838
from ..utils import commons
3939
from ..utils import exceptions
4040
from ..utils.commons import headers, empty_project_json, webscrape_count, get_class_sort_mode
41-
from ..utils.requests import Requests as requests
41+
from ..utils.requests import requests
4242
from .browser_cookies import Browser, ANY, cookies_from_browser
4343

4444
ratelimit_cache: dict[str, list[float]] = {}
@@ -92,7 +92,7 @@ def __str__(self) -> str:
9292
def __init__(self, **entries):
9393
# Info on how the .update method has to fetch the data:
9494
self.update_function = requests.post
95-
self.update_API = "https://scratch.mit.edu/session"
95+
self.update_api = "https://scratch.mit.edu/session"
9696

9797
# Set attributes every Session object needs to have:
9898
self.id = None
@@ -650,9 +650,10 @@ def mystuff_studios(self, filter_arg: str = "all", *, page: int = 1, sort_by: st
650650
ascsort = sort_by
651651
descsort = ""
652652
try:
653+
params: dict[str, Union[str, int]] = {"page": page, "ascsort": ascsort, "descsort": descsort}
653654
targets = requests.get(
654655
f"https://scratch.mit.edu/site-api/galleries/{filter_arg}/",
655-
params={"page": page, "ascsort": ascsort, "descsort": descsort},
656+
params=params,
656657
headers=headers,
657658
cookies=self._cookies,
658659
timeout=10
@@ -1013,6 +1014,12 @@ def connect_filterbot(self, *, log_deletions=True) -> filterbot.Filterbot:
10131014
def get_session_string(self) -> str:
10141015
assert self.session_string
10151016
return self.session_string
1017+
1018+
def get_headers(self) -> dict[str, str]:
1019+
return self._headers
1020+
1021+
def get_cookies(self) -> dict[str, str]:
1022+
return self._cookies
10161023

10171024
# ------ #
10181025

@@ -1119,11 +1126,12 @@ def login(username, password, *, timeout=10) -> Session:
11191126
# Post request to login API:
11201127
_headers = headers.copy()
11211128
_headers["Cookie"] = "scratchcsrftoken=a;scratchlanguage=en;"
1122-
request = requests.post(
1123-
"https://scratch.mit.edu/login/", json={"username": username, "password": password}, headers=_headers,
1129+
with requests.no_error_handling():
1130+
request = requests.post(
1131+
"https://scratch.mit.edu/login/", json={"username": username, "password": password}, headers=_headers,
11241132

1125-
timeout=timeout, errorhandling = False
1126-
)
1133+
timeout=timeout
1134+
)
11271135
try:
11281136
result = re.search('"(.*)"', request.headers["Set-Cookie"])
11291137
assert result is not None

0 commit comments

Comments
 (0)