scratchattach 2.1.11__py3-none-any.whl → 2.1.13__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.
@@ -142,7 +142,7 @@ class WebSocketEventStream(EventStream):
142
142
  i = 0
143
143
  with self.reading:
144
144
  try:
145
- self.receive_new(True)
145
+ self.receive_new(amount != -1)
146
146
  while (self.packets_left and amount == -1) or (amount != -1 and i < amount):
147
147
  if not self.packets_left and amount != -1:
148
148
  self.receive_new()
@@ -150,7 +150,7 @@ class WebSocketEventStream(EventStream):
150
150
  i += 1
151
151
  except Exception:
152
152
  self.source_cloud.reconnect()
153
- self.receive_new(True)
153
+ self.receive_new(amount != -1)
154
154
  while (self.packets_left and amount == -1) or (amount != -1 and i < amount):
155
155
  if not self.packets_left and amount != -1:
156
156
  self.receive_new()
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import warnings
4
- from typing import Optional, Iterable, Self
4
+ from typing import Optional, Iterable
5
+ from typing_extensions import Self
5
6
 
6
7
  from . import base, sprite, mutation, field, inputs, commons, vlb, blockshape, prim, comment, build_defaulting
7
8
  from ..utils import exceptions
@@ -36,7 +36,7 @@ class BaseEventHandler(ABC):
36
36
  self._thread = None
37
37
  self._updater()
38
38
 
39
- def call_event(self, event_name, args=[]):
39
+ def call_event(self, event_name, args : list = []):
40
40
  try:
41
41
  if event_name in self._threaded_events:
42
42
  for func in self._threaded_events[event_name]:
@@ -69,7 +69,6 @@ class CloudRequests(CloudEvents):
69
69
  self._requests = {}
70
70
  self.event(self.on_set, thread=False)
71
71
  self.event(self.on_reconnect, thread=True)
72
- self.respond_in_thread = False
73
72
  self.no_packet_loss = no_packet_loss # When enabled, query the clouddata log regularly for missed requests and reconnect after every single request (reduces packet loss a lot, but is spammy and can make response duration longer)
74
73
  self.used_cloud_vars = used_cloud_vars
75
74
  self.respond_order = respond_order
@@ -106,8 +105,6 @@ class CloudRequests(CloudEvents):
106
105
  """
107
106
  def inner(function):
108
107
  # called if the decorator provides arguments
109
- if thread:
110
- self.respond_in_thread = True
111
108
  self._requests[function.__name__ if name is None else name] = Request(
112
109
  function.__name__ if name is None else name,
113
110
  enabled = enabled,
@@ -302,7 +299,7 @@ class CloudRequests(CloudEvents):
302
299
  request_id=request_id,
303
300
  activity=activity
304
301
  )
305
- self.call_event("on_request", received_request)
302
+ self.call_event("on_request", [received_request])
306
303
  if received_request.request.thread:
307
304
  self.executed_requests[request_id] = received_request
308
305
  Thread(target=received_request.request, args=[received_request]).start() # Execute the request function directly in a thread
@@ -11,7 +11,7 @@ class MultiEventHandler:
11
11
 
12
12
  def event(self, function, *args, **kwargs):
13
13
  for handler in self.handlers:
14
- handler.request(function, *args, **kwargs)
14
+ handler.event(function, *args, **kwargs)
15
15
 
16
16
  def start(self, *args, **kwargs):
17
17
  for handler in self.handlers:
@@ -27,4 +27,4 @@ class MultiEventHandler:
27
27
 
28
28
  def resume(self, *args, **kwargs):
29
29
  for handler in self.handlers:
30
- handler.resume(*args, **kwargs)
30
+ handler.resume(*args, **kwargs)
@@ -14,9 +14,9 @@ class Activity(BaseSiteComponent):
14
14
  """
15
15
 
16
16
  def __repr__(self):
17
- return repr(self.raw)
17
+ return f"Activity({repr(self.raw)})"
18
18
 
19
- def str(self):
19
+ def __str__(self):
20
20
  return str(self.raw)
21
21
 
22
22
  def __init__(self, **entries):
@@ -76,6 +76,7 @@ class Session(BaseSiteComponent):
76
76
  mute_status: Information about commenting restrictions of the associated account
77
77
  banned: Returns True if the associated account is banned
78
78
  """
79
+ session_string: str | None = None
79
80
 
80
81
  def __str__(self) -> str:
81
82
  return f"Login for account {self.username!r}"
@@ -977,6 +978,9 @@ sess
977
978
  def connect_filterbot(self, *, log_deletions=True) -> filterbot.Filterbot:
978
979
  return filterbot.Filterbot(user.User(username=self.username, _session=self), log_deletions=log_deletions)
979
980
 
981
+ def get_session_string(self) -> str:
982
+ assert self.session_string
983
+ return self.session_string
980
984
 
981
985
  # ------ #
982
986
 
@@ -1001,10 +1005,10 @@ def issue_login_warning() -> None:
1001
1005
  if getattr(suppressed_login_warning, "suppressed", 0):
1002
1006
  return
1003
1007
  warnings.warn(
1004
- "IMPORTANT: If you included login credentials directly in your code (e.g. session_id, session_string, ...), \
1005
- then make sure to EITHER instead load them from environment variables or files OR remember to remove them before \
1006
- you share your code with anyone else. If you want to remove this warning, \
1007
- use `warnings.filterwarnings('ignore', category=scratchattach.LoginDataWarning)`",
1008
+ "IMPORTANT: If you included login credentials directly in your code (e.g. session_id, session_string, ...), "
1009
+ "then make sure to EITHER instead load them from environment variables or files OR remember to remove them before "
1010
+ "you share your code with anyone else. If you want to remove this warning, "
1011
+ "use `warnings.filterwarnings('ignore', category=scratchattach.LoginDataWarning)`",
1008
1012
  exceptions.LoginDataWarning
1009
1013
  )
1010
1014
 
@@ -1033,7 +1037,7 @@ def login_by_id(session_id: str, *, username: Optional[str] = None, password: Op
1033
1037
  issue_login_warning()
1034
1038
  if password is not None:
1035
1039
  session_data = dict(session_id=session_id, username=username, password=password)
1036
- session_string = base64.b64encode(json.dumps(session_data).encode())
1040
+ session_string = base64.b64encode(json.dumps(session_data).encode()).decode()
1037
1041
  else:
1038
1042
  session_string = None
1039
1043
  _session = Session(id=session_id, username=username, session_string=session_string, xtoken=xtoken)
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
  import json
5
5
  import random
6
6
  import string
7
+ from datetime import datetime
7
8
 
8
9
  from ..eventhandlers import message_events
9
10
  from . import project
@@ -259,7 +260,7 @@ class User(BaseSiteComponent):
259
260
 
260
261
  def studios_following_count(self):
261
262
  text = requests.get(
262
- f"https://scratch.mit.edu/users/{self.username}/studios/",
263
+ f"https://scratch.mit.edu/users/{self.username}/studios_following/",
263
264
  headers = self._headers
264
265
  ).text
265
266
  return commons.webscrape_count(text, "Studios I Follow (", ")")
@@ -555,6 +556,12 @@ class User(BaseSiteComponent):
555
556
  if '{"error": "isFlood"}' in text:
556
557
  raise(exceptions.CommentPostFailure(
557
558
  "You are being rate-limited for running this operation too often. Implement a cooldown of about 10 seconds."))
559
+ elif '<script id="error-data" type="application/json">' in text:
560
+ raw_error_data = text.split('<script id="error-data" type="application/json">')[1].split('</script>')[0]
561
+ error_data = json.loads(raw_error_data)
562
+ expires = error_data['mute_status']['muteExpiresAt']
563
+ expires = datetime.utcfromtimestamp(expires)
564
+ raise(exceptions.CommentPostFailure(f"You have been muted. Mute expires on {expires}"))
558
565
  else:
559
566
  raise(exceptions.FetchError(f"Couldn't parse API response: {r.text!r}"))
560
567
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scratchattach
3
- Version: 2.1.11
3
+ Version: 2.1.13
4
4
  Summary: A Scratch API Wrapper
5
5
  Home-page: https://scratchattach.tim1de.net
6
6
  Author: TimMcCool
@@ -18,6 +18,7 @@ Requires-Dist: websocket-client
18
18
  Requires-Dist: requests
19
19
  Requires-Dist: bs4
20
20
  Requires-Dist: SimpleWebSocketServer
21
+ Requires-Dist: typing-extensions
21
22
  Dynamic: author
22
23
  Dynamic: classifier
23
24
  Dynamic: description
@@ -1,12 +1,12 @@
1
1
  scratchattach/__init__.py,sha256=2iiV0SghFUyJJrJYt668cSoDrxSjLCWNtzMdhttnMdA,1532
2
2
  scratchattach/cloud/__init__.py,sha256=MN7s4grQcciqUO7TiFjTbU2sC69m6XXlwOHNRbN3FKo,41
3
- scratchattach/cloud/_base.py,sha256=gMaZkiNL0MW7TjSmn_2d8en4GFYF5Bxyy-pPENKrBGc,17753
3
+ scratchattach/cloud/_base.py,sha256=3Kc1VKX6ogDqyItLUbHPom9DeGq7EUjpS0bjr-JuTHQ,17769
4
4
  scratchattach/cloud/cloud.py,sha256=TcIcY0tMe1jRdzxJrz6AIL0gW9xeMc9x4vNUCvBbRWY,7735
5
5
  scratchattach/editor/__init__.py,sha256=gfTQrtyQ-oZJBanp-5eNae72cwm4WoKHzNtZ4rn1dqg,727
6
6
  scratchattach/editor/asset.py,sha256=jNXJA09hU5b4ZTLegu7c0azlwHo5k_XZJfDN24uDux8,6078
7
7
  scratchattach/editor/backpack_json.py,sha256=PZGNIFNf0MS3hn8cKZEp9ZeQWdBE-xWq5PEwiN8IzWM,3900
8
8
  scratchattach/editor/base.py,sha256=Aq_a9tAMgKuaG1mmkVDoPHaV-z1bn1UUz6YcU6jThqc,3914
9
- scratchattach/editor/block.py,sha256=1lqEmR_PK74pGurl-6rDJbGXpfkmCycsyheW-29BFdc,16274
9
+ scratchattach/editor/block.py,sha256=q-xdjmczbI702lp_c4EdBMy5iose88MyluFXz-3ZVx8,16303
10
10
  scratchattach/editor/blockshape.py,sha256=a2WY_UPcLINNS-E2NB7uvnDrE1Z62LFTNybDX5DzZPw,25133
11
11
  scratchattach/editor/build_defaulting.py,sha256=SoIEw6iZO2y23Ry5uK8wLfJXdN3U7k30F3_OKWWYUgk,1254
12
12
  scratchattach/editor/comment.py,sha256=2kZYSAiILSlrWU7RfzNf9PJnuGHVKXLWGzWnD_PW8-M,2250
@@ -25,13 +25,13 @@ scratchattach/editor/sprite.py,sha256=wGDdaaP09UPY0XB9k2qbw9Ac0wwMukno8NPR9tFgOH
25
25
  scratchattach/editor/twconfig.py,sha256=JMqkZNtibH25t6BqXqql9Lv_3cAkMtYpLtX3cZvAu4Q,3313
26
26
  scratchattach/editor/vlb.py,sha256=1ejSsZcolNJ0xlD9nhbP6Gxf881cqJiLwyGri4ZQm1M,4158
27
27
  scratchattach/eventhandlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- scratchattach/eventhandlers/_base.py,sha256=8NjYF7qOEhjUFksA0qKg4XDH5aXgEG5PSVgMAYDbGD4,3078
28
+ scratchattach/eventhandlers/_base.py,sha256=yDTYLqWbFhOEEKcrxhncR8uHRSgom0_7lVkICgcbuBE,3087
29
29
  scratchattach/eventhandlers/cloud_events.py,sha256=iaUFo58D5JUCHstch2VhmhqMPq8WX_xrzPelFMCFRF8,4084
30
30
  scratchattach/eventhandlers/cloud_recorder.py,sha256=o4wcWJFCddpcSsPx5YU2DFFMFoKUknKM2RQ36HLpheQ,800
31
- scratchattach/eventhandlers/cloud_requests.py,sha256=jW3tLpfNmgsVuac5Y7vqx--qu1nQxytTV71Dx6ejGfU,22191
31
+ scratchattach/eventhandlers/cloud_requests.py,sha256=49VB89H1V49L1MVlF0MXbmBRY7pmyLZrsGbfYOcI42o,22085
32
32
  scratchattach/eventhandlers/cloud_server.py,sha256=tah77FTr1Kp4DWpux48w8pJNZQL_1qL0hAXaAXlzQ9Y,12266
33
33
  scratchattach/eventhandlers/cloud_storage.py,sha256=9dvKPxbPZ_hBhw1HYlTl72YJmBo2OMwrSrMQ7kQwwOE,4660
34
- scratchattach/eventhandlers/combine.py,sha256=2n5SC6tSpgrmmK04sqsm4eqx26O9haBKA5YgsWNIoso,895
34
+ scratchattach/eventhandlers/combine.py,sha256=YiWI6WI1BySioXpfYaMv8noBM14EjZa7dtsJsMTshEU,894
35
35
  scratchattach/eventhandlers/filterbot.py,sha256=RvGCm-2iaC8SAC4nDMlDv0MPp80CsRr4CFGmnIuEfg8,7462
36
36
  scratchattach/eventhandlers/message_events.py,sha256=99ez4HdsDKRjVUvPpNolDaOMtHrPlRJa8agi88EYc7E,1764
37
37
  scratchattach/other/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -39,7 +39,7 @@ scratchattach/other/other_apis.py,sha256=7EyB3uB-1AYAH7Nb6eZ3VmACGdXvEQ39NJ1iahU
39
39
  scratchattach/other/project_json_capabilities.py,sha256=qSlJIJOgAxhSchD3fOIhK57rCe0_GrHadXBs5UXKuFU,22622
40
40
  scratchattach/site/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  scratchattach/site/_base.py,sha256=S-ynYKe7LslZxaZzE0hZsga0eLB2XlQo5erAfKct8yc,2193
42
- scratchattach/site/activity.py,sha256=a019lhoUwL9mdZI1Sz9mMg9EsDt2Lp5ziJSSDQ8-BWM,14319
42
+ scratchattach/site/activity.py,sha256=fczH9_v5CoFuMTobm7BcbnMy2scf9c2ZjzfIqBEOBes,14338
43
43
  scratchattach/site/backpack_asset.py,sha256=V_ypvTi-hqf0LF8zks2uHIicraBssc1_eEHVqHMzikc,3286
44
44
  scratchattach/site/browser_cookies.py,sha256=aaYLawtifngZ0pgaXHjBiWvYHUfflS8ZcXRjTTrge3A,1566
45
45
  scratchattach/site/classroom.py,sha256=WKMOcmYzKZx_EZNR4qipHOB8nxaggFe84lxqnrWd24E,16463
@@ -47,17 +47,17 @@ scratchattach/site/cloud_activity.py,sha256=ie_DhChicks_RBagMM6_GfFIi1iAxf6UtJ3V
47
47
  scratchattach/site/comment.py,sha256=Yt86iqwKZhCKNTEvB9DNDj9mXRV6A9qXyy1MrE7rMnA,8377
48
48
  scratchattach/site/forum.py,sha256=BZ_2jqDW3o-22AG1vP9s1W7l9yBbjBkFqG_DGV9IDuA,14802
49
49
  scratchattach/site/project.py,sha256=_yMzacrTiy_LYfyEfWVeoHRHm5t9vBUr88eR_ULcK7Q,30931
50
- scratchattach/site/session.py,sha256=mP4tTSZUs9dz0e3Zk6JF9RmSizFaYExbbEEYmA5TBnM,48278
50
+ scratchattach/site/session.py,sha256=0R3siN6CUjCHcQ-0oa27m5NBHjMULYheZamtmGQ0KEM,48439
51
51
  scratchattach/site/studio.py,sha256=Tv7AY1TwvlQpR9VjUEs-qmavrZsLxchkXk59aoH0_EI,22918
52
- scratchattach/site/user.py,sha256=TCO1QRtPeJdb3p-ziCwa6NqObHSNP0DMmcOl5De-Yl8,34496
52
+ scratchattach/site/user.py,sha256=20fnNj_HL339xtmHq0OGAxAAXfWvhBUmbM5UDoa_RWI,35024
53
53
  scratchattach/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  scratchattach/utils/commons.py,sha256=6yCfUvQlQbl2VPhxJiK1MSdBdXpBbkr5uYyB2LLIcdI,8155
55
55
  scratchattach/utils/encoder.py,sha256=rqJfQ5gmjf7s8aTiGhR0W1ejYN5tHbAgJlxv7JhGqZQ,2479
56
56
  scratchattach/utils/enums.py,sha256=93ylCrxWycunahISSIjBqTIJ2r1Hb2b9RMvvzmUiQ-c,8294
57
57
  scratchattach/utils/exceptions.py,sha256=hrnPuXRRwR-kTHnrQVyfAD6PDOg1hZQd-jaXuUSNKSQ,6274
58
58
  scratchattach/utils/requests.py,sha256=x_EfcbLdBpQQuH9g4MMSaM8RN3tUm9OtzPEJQQiwilY,2709
59
- scratchattach-2.1.11.dist-info/licenses/LICENSE,sha256=1PRKLhZU4wYt5M-C9f7q0W3go3u_ojnZMNOdR3g3J-E,1080
60
- scratchattach-2.1.11.dist-info/METADATA,sha256=mC-Kltdsi4hFeQOpg44My3rIvG831mrvMJJdQGMLngY,5463
61
- scratchattach-2.1.11.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
62
- scratchattach-2.1.11.dist-info/top_level.txt,sha256=gIwCwW39ohXn0JlnvSzAjV7VtL3qPlRnHiRqBbxsEUE,14
63
- scratchattach-2.1.11.dist-info/RECORD,,
59
+ scratchattach-2.1.13.dist-info/licenses/LICENSE,sha256=1PRKLhZU4wYt5M-C9f7q0W3go3u_ojnZMNOdR3g3J-E,1080
60
+ scratchattach-2.1.13.dist-info/METADATA,sha256=M5czwHWY0s6qbdYrPBhI6Qo7N5dP9VGFX0f_I0fcsDU,5496
61
+ scratchattach-2.1.13.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
62
+ scratchattach-2.1.13.dist-info/top_level.txt,sha256=gIwCwW39ohXn0JlnvSzAjV7VtL3qPlRnHiRqBbxsEUE,14
63
+ scratchattach-2.1.13.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5