scratchattach 2.1.15b0__py3-none-any.whl → 3.0.0b1__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.
Files changed (87) hide show
  1. cli/__about__.py +1 -0
  2. cli/__init__.py +26 -0
  3. cli/cmd/__init__.py +4 -0
  4. cli/cmd/group.py +127 -0
  5. cli/cmd/login.py +60 -0
  6. cli/cmd/profile.py +7 -0
  7. cli/cmd/sessions.py +5 -0
  8. cli/context.py +142 -0
  9. cli/db.py +66 -0
  10. cli/namespace.py +14 -0
  11. {scratchattach/cloud → cloud}/_base.py +112 -87
  12. {scratchattach/cloud → cloud}/cloud.py +16 -16
  13. {scratchattach/editor → editor}/__init__.py +2 -1
  14. {scratchattach/editor → editor}/asset.py +26 -14
  15. {scratchattach/editor → editor}/backpack_json.py +3 -5
  16. {scratchattach/editor → editor}/base.py +2 -4
  17. {scratchattach/editor → editor}/block.py +27 -22
  18. {scratchattach/editor → editor}/blockshape.py +1 -1
  19. {scratchattach/editor → editor}/build_defaulting.py +2 -2
  20. editor/commons.py +145 -0
  21. {scratchattach/editor → editor}/field.py +1 -1
  22. {scratchattach/editor → editor}/inputs.py +6 -3
  23. {scratchattach/editor → editor}/meta.py +10 -7
  24. {scratchattach/editor → editor}/monitor.py +10 -8
  25. {scratchattach/editor → editor}/mutation.py +68 -11
  26. {scratchattach/editor → editor}/pallete.py +1 -3
  27. {scratchattach/editor → editor}/prim.py +4 -0
  28. {scratchattach/editor → editor}/project.py +118 -16
  29. {scratchattach/editor → editor}/sprite.py +25 -15
  30. {scratchattach/editor → editor}/vlb.py +2 -2
  31. {scratchattach/eventhandlers → eventhandlers}/_base.py +1 -0
  32. {scratchattach/eventhandlers → eventhandlers}/cloud_events.py +26 -6
  33. {scratchattach/eventhandlers → eventhandlers}/cloud_recorder.py +4 -4
  34. {scratchattach/eventhandlers → eventhandlers}/cloud_requests.py +139 -54
  35. {scratchattach/eventhandlers → eventhandlers}/cloud_server.py +6 -3
  36. {scratchattach/eventhandlers → eventhandlers}/cloud_storage.py +1 -2
  37. eventhandlers/filterbot.py +163 -0
  38. other/other_apis.py +598 -0
  39. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b1.dist-info}/METADATA +7 -11
  40. scratchattach-3.0.0b1.dist-info/RECORD +79 -0
  41. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b1.dist-info}/WHEEL +1 -1
  42. scratchattach-3.0.0b1.dist-info/entry_points.txt +2 -0
  43. scratchattach-3.0.0b1.dist-info/top_level.txt +7 -0
  44. {scratchattach/site → site}/_base.py +32 -5
  45. site/activity.py +426 -0
  46. {scratchattach/site → site}/alert.py +4 -5
  47. {scratchattach/site → site}/backpack_asset.py +2 -1
  48. {scratchattach/site → site}/classroom.py +80 -73
  49. {scratchattach/site → site}/cloud_activity.py +43 -29
  50. {scratchattach/site → site}/comment.py +86 -100
  51. {scratchattach/site → site}/forum.py +8 -4
  52. site/placeholder.py +132 -0
  53. {scratchattach/site → site}/project.py +228 -122
  54. {scratchattach/site → site}/session.py +156 -71
  55. {scratchattach/site → site}/studio.py +139 -46
  56. site/typed_dicts.py +151 -0
  57. {scratchattach/site → site}/user.py +511 -215
  58. {scratchattach/utils → utils}/commons.py +12 -4
  59. {scratchattach/utils → utils}/encoder.py +7 -4
  60. {scratchattach/utils → utils}/enums.py +1 -0
  61. {scratchattach/utils → utils}/exceptions.py +36 -2
  62. utils/optional_async.py +154 -0
  63. utils/requests.py +306 -0
  64. scratchattach/__init__.py +0 -29
  65. scratchattach/editor/commons.py +0 -273
  66. scratchattach/eventhandlers/filterbot.py +0 -161
  67. scratchattach/other/other_apis.py +0 -284
  68. scratchattach/site/activity.py +0 -382
  69. scratchattach/utils/requests.py +0 -93
  70. scratchattach-2.1.15b0.dist-info/RECORD +0 -66
  71. scratchattach-2.1.15b0.dist-info/top_level.txt +0 -1
  72. {scratchattach/cloud → cloud}/__init__.py +0 -0
  73. {scratchattach/editor → editor}/code_translation/__init__.py +0 -0
  74. {scratchattach/editor → editor}/code_translation/parse.py +0 -0
  75. {scratchattach/editor → editor}/comment.py +0 -0
  76. {scratchattach/editor → editor}/extension.py +0 -0
  77. {scratchattach/editor → editor}/twconfig.py +0 -0
  78. {scratchattach/eventhandlers → eventhandlers}/__init__.py +0 -0
  79. {scratchattach/eventhandlers → eventhandlers}/combine.py +0 -0
  80. {scratchattach/eventhandlers → eventhandlers}/message_events.py +0 -0
  81. {scratchattach/other → other}/__init__.py +0 -0
  82. {scratchattach/other → other}/project_json_capabilities.py +0 -0
  83. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b1.dist-info}/licenses/LICENSE +0 -0
  84. {scratchattach/site → site}/__init__.py +0 -0
  85. {scratchattach/site → site}/browser_cookie3_stub.py +0 -0
  86. {scratchattach/site → site}/browser_cookies.py +0 -0
  87. {scratchattach/utils → utils}/__init__.py +0 -0
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
 
4
4
  import string
5
5
 
6
- from typing import Optional, Final, Any, TypeVar, Callable, TYPE_CHECKING, Union
6
+ from typing import Optional, Final, Any, TypeVar, Callable, TYPE_CHECKING, Union, overload
7
7
  from threading import Event as ManualResetEvent
8
8
  from threading import Lock
9
9
 
@@ -162,19 +162,28 @@ def _get_object(identificator_name, identificator, __class: type[C], NotFoundExc
162
162
  except Exception as e:
163
163
  raise e
164
164
 
165
+ I = TypeVar("I")
166
+ @overload
167
+ def webscrape_count(raw: str, text_before: str, text_after: str, cls: type[I]) -> I:
168
+ pass
165
169
 
166
- def webscrape_count(raw, text_before, text_after, cls: type = int) -> int | Any:
170
+ @overload
171
+ def webscrape_count(raw: str, text_before: str, text_after: str) -> int:
172
+ pass
173
+
174
+ def webscrape_count(raw, text_before, text_after, cls = int):
167
175
  return cls(raw.split(text_before)[1].split(text_after)[0])
168
176
 
169
177
 
170
178
  if TYPE_CHECKING:
171
179
  C = TypeVar("C", bound=_base.BaseSiteComponent)
172
180
 
173
- def parse_object_list(raw, __class: type[C], session=None, primary_key="id") -> list[C]:
181
+ def parse_object_list(raw, /, __class: type[C], session=None, primary_key="id") -> list[C]:
174
182
  results = []
175
183
  for raw_dict in raw:
176
184
  try:
177
185
  _obj = __class(**{primary_key: raw_dict[primary_key], "_session": session})
186
+ # noinspection PyProtectedMember
178
187
  _obj._update_from_dict(raw_dict)
179
188
  results.append(_obj)
180
189
  except Exception as e:
@@ -252,4 +261,3 @@ def b62_decode(s: str):
252
261
  ret = ret * 62 + chars.index(char)
253
262
 
254
263
  return ret
255
-
@@ -122,11 +122,14 @@ class Encoding:
122
122
  try:
123
123
  inp = str(inp)
124
124
  except Exception:
125
- raise(exceptions.InvalidDecodeInput)
125
+ raise exceptions.InvalidDecodeInput
126
+
126
127
  outp = ""
127
- for i in range(0, math.floor(len(inp) / 2)):
128
- letter = letters[int(f"{inp[i*2]}{inp[(i*2)+1]}")]
129
- outp = f"{outp}{letter}"
128
+ # print(f"Encoding.decode({inp=})")
129
+ # This loops through a string like 'abCDefGHijKLmnOP' like so: l1+l2=ab, CD, ef, GH, etc.
130
+ for l1, l2 in zip(inp[::2], inp[1::2]):
131
+ outp += letters[int(l1 + l2)]
132
+
130
133
  return outp
131
134
 
132
135
  @staticmethod
@@ -18,6 +18,7 @@ class Language:
18
18
  single_gender: bool = None
19
19
 
20
20
 
21
+ # should this underscore be removed
21
22
  class _EnumWrapper(Enum):
22
23
  @classmethod
23
24
  def find(cls, value, by: str, apply_func: Optional[Callable] = None):
@@ -232,9 +232,43 @@ class LoginDataWarning(UserWarning):
232
232
  Warns you not to accidentally share your login data.
233
233
  """
234
234
 
235
- class AnonymousSiteComponentWarning(UserWarning):
235
+ class InvalidUpdateWarning(UserWarning):
236
236
  """
237
- Warns about a usage of an anonymous site component.
237
+ Warns you that something cannot be updated.
238
+ """
239
+
240
+ class GetAuthenticationWarning(UserWarning):
241
+ """
242
+ All authentication warnings.
243
+ """
244
+
245
+ class UserAuthenticationWarning(GetAuthenticationWarning):
246
+ """
247
+ Warns you to use session.connect_user instead of user.get_user
248
+ for actions that require authentication.
249
+ """
250
+
251
+ class ProjectAuthenticationWarning(GetAuthenticationWarning):
252
+ """
253
+ Warns you to use session.connect_project instead of project.get_project
254
+ for actions that require authentication.
255
+ """
256
+
257
+ class StudioAuthenticationWarning(GetAuthenticationWarning):
258
+ """
259
+ Warns you to use session.connect_studio instead of studio.get_studio
260
+ for actions that require authentication.
261
+ """
262
+
263
+ class ClassroomAuthenticationWarning(GetAuthenticationWarning):
264
+ """
265
+ Warns you to use session.connect_classroom or session.connect_classroom_from_token instead of classroom.get_classroom
266
+ for actions that require authentication.
267
+ """
268
+
269
+ class CloudAuthenticationWarning(GetAuthenticationWarning):
270
+ """
271
+ Warns you about usage of
238
272
  """
239
273
 
240
274
  class UnexpectedWebsocketEventWarning(RuntimeWarning):
@@ -0,0 +1,154 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from collections.abc import Awaitable, Generator, Callable
5
+ from typing import Generic, TypeVar, ParamSpec, Optional, Union, Any
6
+ from functools import wraps
7
+ import asyncio
8
+ import time
9
+
10
+ from . import requests
11
+
12
+ P = ParamSpec("P")
13
+ R = TypeVar("R")
14
+
15
+ class CallableAwaitable(Generic[R], ABC, Awaitable[R]):
16
+ result: R
17
+
18
+ @abstractmethod
19
+ def sync_impl(self) -> R:
20
+ pass
21
+
22
+ def __pos__(self) -> R:
23
+ return self.sync_impl()
24
+
25
+ @abstractmethod
26
+ async def async_impl(self) -> R:
27
+ pass
28
+
29
+ def __await__(self) -> Generator[None, None, R]:
30
+ return self.async_impl().__await__()
31
+
32
+ class OptionallyAsync(Generic[P, R], ABC):
33
+ @abstractmethod
34
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> CallableAwaitable[R]:
35
+ pass
36
+
37
+ def optionally_async(func: Callable[P, Generator[CallableAwaitable, None, R]]) -> OptionallyAsync[P, R]:
38
+ class Wrapped(OptionallyAsync[P, R]):
39
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> CallableAwaitable[R]:
40
+ class Implementation(CallableAwaitable[R]):
41
+ def sync_impl(self) -> R:
42
+ i = func(*args, **kwargs)
43
+ try:
44
+ while True:
45
+ c = next(i)
46
+ c.result = +c
47
+ except StopIteration as excp:
48
+ return excp.value
49
+
50
+ async def async_impl(self) -> R:
51
+ i = func(*args, **kwargs)
52
+ try:
53
+ while True:
54
+ c = next(i)
55
+ c.result = await c
56
+ except StopIteration as excp:
57
+ return excp.value
58
+
59
+ return Implementation()
60
+ return Wrapped()
61
+
62
+ def make_async(func: Callable[P, Generator[CallableAwaitable, None, R]]) -> Callable[P, Awaitable[R]]:
63
+ @wraps(func)
64
+ async def async_impl(*args: P.args, **kwargs: P.kwargs) -> R:
65
+ i = func(*args, **kwargs)
66
+ try:
67
+ while True:
68
+ c = next(i)
69
+ c.result = await c
70
+ except StopIteration as excp:
71
+ return excp.value
72
+ return async_impl
73
+
74
+ def make_sync(func: Callable[P, Generator[CallableAwaitable, None, R]]) -> Callable[P, R]:
75
+ @wraps(func)
76
+ def sync_impl(*args: P.args, **kwargs: P.kwargs) -> R:
77
+ i = func(*args, **kwargs)
78
+ try:
79
+ while True:
80
+ c = next(i)
81
+ c.result = +c
82
+ except StopIteration as excp:
83
+ return excp.value
84
+ return sync_impl
85
+
86
+ class CASleep(CallableAwaitable[bool]):
87
+ amount: float
88
+
89
+ def __init__(self, amount: float) -> None:
90
+ self.amount = amount
91
+
92
+ def sync_impl(self):
93
+ time.sleep(self.amount)
94
+ return True
95
+
96
+ async def async_impl(self):
97
+ await asyncio.sleep(self.amount)
98
+ return True
99
+
100
+ def oa_sleep(amount: float):
101
+ return CASleep(amount)
102
+
103
+ class CARequest(CallableAwaitable["requests.AnyHTTPResponse"]):
104
+ requests_session: requests.OAHTTPSession
105
+ method: requests.HTTPMethod
106
+ url: str
107
+ cookies: Optional[dict[str, str]]
108
+ headers: Optional[dict[str, str]]
109
+ params: Optional[dict[str, str]]
110
+ data: Optional[Union[dict[str, str], str]]
111
+ json: Optional[dict[str, str]]
112
+
113
+ def __init__(
114
+ self,
115
+ requests_session: requests.OAHTTPSession,
116
+ method: requests.HTTPMethod,
117
+ url: str,
118
+ *,
119
+ cookies: Optional[dict[str, str]] = None,
120
+ headers: Optional[dict[str, str]] = None,
121
+ params: Optional[dict[str, str]] = None,
122
+ data: Optional[Union[dict[str, str], str]] = None,
123
+ json: Optional[Any] = None
124
+ ) -> None:
125
+ self.requests_session = requests_session
126
+ self.method = method
127
+ self.url = url
128
+ self.cookies = cookies
129
+ self.headers = headers
130
+ self.params = params
131
+ self.data = data
132
+ self.json = json
133
+
134
+ def sync_impl(self):
135
+ return self.requests_session.sync_request(
136
+ method = self.method,
137
+ url = self.url,
138
+ cookies = self.cookies,
139
+ headers = self.headers,
140
+ params = self.params,
141
+ data = self.data,
142
+ json = self.json
143
+ )
144
+
145
+ async def async_impl(self):
146
+ return await self.requests_session.async_request(
147
+ method = self.method,
148
+ url = self.url,
149
+ cookies = self.cookies,
150
+ headers = self.headers,
151
+ params = self.params,
152
+ data = self.data,
153
+ json = self.json
154
+ )
utils/requests.py ADDED
@@ -0,0 +1,306 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import MutableMapping, Iterator
4
+ from abc import ABC, abstractmethod
5
+ from types import TracebackType
6
+ from typing import Optional, Any, Self, Union
7
+ from contextlib import contextmanager
8
+ from enum import Enum, auto
9
+ from dataclasses import dataclass, field
10
+ import json
11
+
12
+ from aiohttp.cookiejar import DummyCookieJar
13
+ from typing_extensions import override
14
+ from requests import Session as HTTPSession
15
+ from requests import Response
16
+ import aiohttp
17
+
18
+ from . import exceptions
19
+ from . import optional_async
20
+
21
+ proxies: Optional[MutableMapping[str, str]] = None
22
+
23
+ class HTTPMethod(Enum):
24
+ GET = auto()
25
+ POST = auto()
26
+ PUT = auto()
27
+ DELETE = auto()
28
+ HEAD = auto()
29
+ OPTIONS = auto()
30
+ PATCH = auto()
31
+ TRACE = auto()
32
+ @classmethod
33
+ def of(cls, name: str) -> HTTPMethod:
34
+ member_map = {
35
+ "GET": cls.GET,
36
+ "POST": cls.POST,
37
+ "PUT": cls.PUT,
38
+ "DELETE": cls.DELETE,
39
+ "HEAD": cls.HEAD,
40
+ "OPTIONS": cls.OPTIONS,
41
+ "PATCH": cls.PATCH,
42
+ "TRACE": cls.TRACE
43
+ }
44
+ return member_map[name]
45
+
46
+ class AnyHTTPResponse(ABC):
47
+ request_method: HTTPMethod
48
+ status_code: int
49
+ content: bytes
50
+ text: str
51
+ headers: dict[str, str]
52
+
53
+ def json(self) -> Any:
54
+ return json.loads(self.text)
55
+
56
+ @dataclass
57
+ class HTTPResponse(AnyHTTPResponse):
58
+ request_method: HTTPMethod = field(kw_only=True)
59
+ status_code: int = field(kw_only=True)
60
+ content: bytes = field(kw_only=True)
61
+ text: str = field(kw_only=True)
62
+ headers: dict[str, str] = field(kw_only=True)
63
+
64
+ class OAHTTPSession(ABC):
65
+ error_handling: bool = True
66
+ @abstractmethod
67
+ def sync_request(
68
+ self,
69
+ method: HTTPMethod,
70
+ url: str,
71
+ *,
72
+ cookies: Optional[dict[str, str]] = None,
73
+ headers: Optional[dict[str, str]] = None,
74
+ params: Optional[dict[str, str]] = None,
75
+ data: Optional[Union[dict[str, str], str]] = None,
76
+ json: Optional[Any] = None
77
+ ) -> AnyHTTPResponse:
78
+ pass
79
+
80
+ @abstractmethod
81
+ async def async_request(
82
+ self,
83
+ method: HTTPMethod,
84
+ url: str,
85
+ *,
86
+ cookies: Optional[dict[str, str]] = None,
87
+ headers: Optional[dict[str, str]] = None,
88
+ params: Optional[dict[str, str]] = None,
89
+ data: Optional[Union[dict[str, str], str]] = None,
90
+ json: Optional[Any] = None
91
+ ) -> AnyHTTPResponse:
92
+ pass
93
+
94
+ def check_response(self, r: AnyHTTPResponse):
95
+ if r.status_code == 403 or r.status_code == 401:
96
+ raise exceptions.Unauthorized(f"Request content: {r.content!r}")
97
+ if r.status_code == 500:
98
+ raise exceptions.APIError("Internal Scratch server error")
99
+ if r.status_code == 429:
100
+ raise exceptions.Response429("You are being rate-limited (or blocked) by Scratch")
101
+ if r.json() == {"code":"BadRequest","message":""}:
102
+ raise exceptions.BadRequest("Make sure all provided arguments are valid")
103
+
104
+
105
+ def request(
106
+ self,
107
+ method: Union[HTTPMethod, str],
108
+ url: str,
109
+ *,
110
+ cookies: Optional[dict[str, str]] = None,
111
+ headers: Optional[dict[str, str]] = None,
112
+ params: Optional[dict[str, str]] = None,
113
+ data: Optional[Union[dict[str, str], str]] = None,
114
+ json: Optional[Any] = None
115
+ ) -> optional_async.CARequest:
116
+ if isinstance(method, str):
117
+ method = HTTPMethod.of(method.upper())
118
+ return optional_async.CARequest(
119
+ self,
120
+ method,
121
+ url,
122
+ cookies = cookies,
123
+ headers = headers,
124
+ params = params,
125
+ data = data,
126
+ json = json
127
+ )
128
+
129
+ @contextmanager
130
+ def no_error_handling(self) -> Iterator[None]:
131
+ val_before = self.error_handling
132
+ self.error_handling = False
133
+ try:
134
+ yield
135
+ finally:
136
+ self.error_handling = val_before
137
+
138
+ @contextmanager
139
+ def yes_error_handling(self) -> Iterator[None]:
140
+ val_before = self.error_handling
141
+ self.error_handling = True
142
+ try:
143
+ yield
144
+ finally:
145
+ self.error_handling = val_before
146
+
147
+ class SyncRequests(OAHTTPSession):
148
+ @override
149
+ def sync_request(self, method, url, *, cookies = None, headers = None, params = None, data = None, json = None):
150
+ try:
151
+ r = requests.request(
152
+ method.name,
153
+ url,
154
+ cookies = cookies,
155
+ headers = headers,
156
+ params = params,
157
+ data = data,
158
+ json = json,
159
+ proxies = proxies
160
+ )
161
+ except Exception as e:
162
+ raise exceptions.FetchError(e)
163
+ response = HTTPResponse(
164
+ request_method=method,
165
+ status_code=r.status_code,
166
+ content=r.content,
167
+ text=r.text,
168
+ headers=r.headers
169
+ )
170
+ if self.error_handling:
171
+ self.check_response(response)
172
+ return response
173
+
174
+ async def async_request(self, method, url, *, cookies = None, headers = None, params = None, data = None, json = None):
175
+ raise NotImplementedError()
176
+
177
+ class AsyncRequests(OAHTTPSession):
178
+ client_session: aiohttp.ClientSession
179
+ async def __aenter__(self) -> Self:
180
+ self.client_session = await aiohttp.ClientSession(cookie_jar=DummyCookieJar()).__aenter__()
181
+ return self
182
+
183
+ async def __aexit__(
184
+ self,
185
+ exc_type: Optional[type[BaseException]] = None,
186
+ exc_val: Optional[BaseException] = None,
187
+ exc_tb: Optional[TracebackType] = None
188
+ ) -> None:
189
+ await self.client_session.__aexit__(exc_type, exc_val, exc_tb)
190
+
191
+ @override
192
+ def sync_request(self, method, url, *, cookies = None, headers = None, params = None, data = None, json = None):
193
+ raise NotImplementedError()
194
+
195
+ async def async_request(self, method, url, *, cookies = None, headers = None, params = None, data = None, json = None):
196
+ proxy = None
197
+ if url.startswith("http"):
198
+ proxy = proxies.get("http")
199
+ if url.startswith("https"):
200
+ proxy = proxies.get("https")
201
+ async with self.client_session.request(
202
+ method.name,
203
+ url,
204
+ cookies = cookies,
205
+ headers = headers,
206
+ params = params,
207
+ data = data,
208
+ json = json,
209
+ proxy = proxy
210
+ ) as resp:
211
+ assert isinstance(resp, aiohttp.ClientResponse)
212
+ content = await resp.read()
213
+ try:
214
+ text = content.decode(resp.get_encoding())
215
+ except Exception:
216
+ text = ""
217
+ response = HTTPResponse(
218
+ request_method=method,
219
+ status_code=resp.status,
220
+ content=content,
221
+ text=text,
222
+ headers=resp.headers
223
+ )
224
+ if self.error_handling:
225
+ self.check_response(response)
226
+ return response
227
+
228
+ class Requests(HTTPSession):
229
+ """
230
+ Centralized HTTP request handler (for better error handling and proxies)
231
+ """
232
+ error_handling: bool = True
233
+
234
+ def check_response(self, r: Response):
235
+ if r.status_code == 403 or r.status_code == 401:
236
+ raise exceptions.Unauthorized(f"Request content: {r.content!r}")
237
+ if r.status_code == 500:
238
+ raise exceptions.APIError("Internal Scratch server error")
239
+ if r.status_code == 429:
240
+ raise exceptions.Response429("You are being rate-limited (or blocked) by Scratch")
241
+ if r.json() == {"code":"BadRequest","message":""}:
242
+ raise exceptions.BadRequest("Make sure all provided arguments are valid")
243
+
244
+ @override
245
+ def get(self, *args, **kwargs):
246
+ kwargs.setdefault("proxies", proxies)
247
+ try:
248
+ r = super().get(*args, **kwargs)
249
+ except Exception as e:
250
+ raise exceptions.FetchError(e)
251
+ if self.error_handling:
252
+ self.check_response(r)
253
+ return r
254
+
255
+ @override
256
+ def post(self, *args, **kwargs):
257
+ kwargs.setdefault("proxies", proxies)
258
+ try:
259
+ r = super().post(*args, **kwargs)
260
+ except Exception as e:
261
+ raise exceptions.FetchError(e)
262
+ if self.error_handling:
263
+ self.check_response(r)
264
+ return r
265
+
266
+ @override
267
+ def delete(self, *args, **kwargs):
268
+ kwargs.setdefault("proxies", proxies)
269
+ try:
270
+ r = super().delete(*args, **kwargs)
271
+ except Exception as e:
272
+ raise exceptions.FetchError(e)
273
+ if self.error_handling:
274
+ self.check_response(r)
275
+ return r
276
+
277
+ @override
278
+ def put(self, *args, **kwargs):
279
+ kwargs.setdefault("proxies", proxies)
280
+ try:
281
+ r = super().put(*args, **kwargs)
282
+ except Exception as e:
283
+ raise exceptions.FetchError(e)
284
+ if self.error_handling:
285
+ self.check_response(r)
286
+ return r
287
+
288
+ @contextmanager
289
+ def no_error_handling(self) -> Iterator[None]:
290
+ val_before = self.error_handling
291
+ self.error_handling = False
292
+ try:
293
+ yield
294
+ finally:
295
+ self.error_handling = val_before
296
+
297
+ @contextmanager
298
+ def yes_error_handling(self) -> Iterator[None]:
299
+ val_before = self.error_handling
300
+ self.error_handling = True
301
+ try:
302
+ yield
303
+ finally:
304
+ self.error_handling = val_before
305
+
306
+ requests = Requests()
scratchattach/__init__.py DELETED
@@ -1,29 +0,0 @@
1
- from .cloud.cloud import ScratchCloud, TwCloud, get_cloud, get_scratch_cloud, get_tw_cloud
2
- from .cloud._base import BaseCloud, AnyCloud
3
-
4
- from .eventhandlers.cloud_server import init_cloud_server
5
- from .eventhandlers._base import BaseEventHandler
6
- from .eventhandlers.filterbot import Filterbot, HardFilter, SoftFilter, SpamFilter
7
- from .eventhandlers.cloud_storage import Database
8
- from .eventhandlers.combine import MultiEventHandler
9
-
10
- from .other.other_apis import *
11
- from .other.project_json_capabilities import ProjectBody, get_empty_project_pb, get_pb_from_dict, read_sb3_file, download_asset
12
- from .utils.encoder import Encoding
13
- from .utils.enums import Languages, TTSVoices
14
- from .utils.exceptions import LoginDataWarning
15
-
16
- from .site.activity import Activity
17
- from .site.backpack_asset import BackpackAsset
18
- from .site.comment import Comment
19
- from .site.cloud_activity import CloudActivity
20
- from .site.forum import ForumPost, ForumTopic, get_topic, get_topic_list, youtube_link_to_scratch
21
- from .site.project import Project, get_project, search_projects, explore_projects
22
- from .site.session import Session, login, login_by_id, login_by_session_string, login_by_io, login_by_file, login_from_browser
23
- from .site.studio import Studio, get_studio, search_studios, explore_studios
24
- from .site.classroom import Classroom, get_classroom
25
- from .site.user import User, get_user
26
- from .site._base import BaseSiteComponent
27
- from .site.browser_cookies import Browser, ANY, FIREFOX, CHROME, CHROMIUM, VIVALDI, EDGE, EDGE_DEV, SAFARI
28
-
29
- from . import editor