scratchattach 2.1.11__tar.gz → 2.1.13__tar.gz

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 (70) hide show
  1. {scratchattach-2.1.11 → scratchattach-2.1.13}/PKG-INFO +2 -1
  2. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/cloud/_base.py +2 -2
  3. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/block.py +2 -1
  4. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/_base.py +1 -1
  5. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/cloud_requests.py +1 -4
  6. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/combine.py +2 -2
  7. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/activity.py +2 -2
  8. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/session.py +9 -5
  9. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/user.py +8 -1
  10. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach.egg-info/PKG-INFO +2 -1
  11. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach.egg-info/SOURCES.txt +1 -0
  12. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach.egg-info/requires.txt +1 -0
  13. {scratchattach-2.1.11 → scratchattach-2.1.13}/setup.py +2 -2
  14. scratchattach-2.1.13/tests/test1.py +20 -0
  15. {scratchattach-2.1.11 → scratchattach-2.1.13}/LICENSE +0 -0
  16. {scratchattach-2.1.11 → scratchattach-2.1.13}/README.md +0 -0
  17. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/__init__.py +0 -0
  18. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/cloud/__init__.py +0 -0
  19. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/cloud/cloud.py +0 -0
  20. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/__init__.py +0 -0
  21. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/asset.py +0 -0
  22. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/backpack_json.py +0 -0
  23. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/base.py +0 -0
  24. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/blockshape.py +0 -0
  25. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/build_defaulting.py +0 -0
  26. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/comment.py +0 -0
  27. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/commons.py +0 -0
  28. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/extension.py +0 -0
  29. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/field.py +0 -0
  30. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/inputs.py +0 -0
  31. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/meta.py +0 -0
  32. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/monitor.py +0 -0
  33. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/mutation.py +0 -0
  34. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/pallete.py +0 -0
  35. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/prim.py +0 -0
  36. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/project.py +0 -0
  37. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/sbuild.py +0 -0
  38. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/sprite.py +0 -0
  39. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/twconfig.py +0 -0
  40. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/editor/vlb.py +0 -0
  41. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/__init__.py +0 -0
  42. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/cloud_events.py +0 -0
  43. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/cloud_recorder.py +0 -0
  44. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/cloud_server.py +0 -0
  45. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/cloud_storage.py +0 -0
  46. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/filterbot.py +0 -0
  47. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/eventhandlers/message_events.py +0 -0
  48. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/other/__init__.py +0 -0
  49. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/other/other_apis.py +0 -0
  50. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/other/project_json_capabilities.py +0 -0
  51. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/__init__.py +0 -0
  52. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/_base.py +0 -0
  53. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/backpack_asset.py +0 -0
  54. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/browser_cookies.py +0 -0
  55. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/classroom.py +0 -0
  56. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/cloud_activity.py +0 -0
  57. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/comment.py +0 -0
  58. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/forum.py +0 -0
  59. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/project.py +0 -0
  60. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/site/studio.py +0 -0
  61. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/utils/__init__.py +0 -0
  62. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/utils/commons.py +0 -0
  63. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/utils/encoder.py +0 -0
  64. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/utils/enums.py +0 -0
  65. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/utils/exceptions.py +0 -0
  66. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach/utils/requests.py +0 -0
  67. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach.egg-info/dependency_links.txt +0 -0
  68. {scratchattach-2.1.11 → scratchattach-2.1.13}/scratchattach.egg-info/top_level.txt +0 -0
  69. {scratchattach-2.1.11 → scratchattach-2.1.13}/setup.cfg +0 -0
  70. {scratchattach-2.1.11 → scratchattach-2.1.13}/tests/test_import.py +0 -0
@@ -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
@@ -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
@@ -64,4 +64,5 @@ scratchattach/utils/encoder.py
64
64
  scratchattach/utils/enums.py
65
65
  scratchattach/utils/exceptions.py
66
66
  scratchattach/utils/requests.py
67
+ tests/test1.py
67
68
  tests/test_import.py
@@ -2,3 +2,4 @@ websocket-client
2
2
  requests
3
3
  bs4
4
4
  SimpleWebSocketServer
5
+ typing-extensions
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
  import codecs
3
3
  import os
4
4
 
5
- VERSION = '2.1.11'
5
+ VERSION = '2.1.13'
6
6
  DESCRIPTION = 'A Scratch API Wrapper'
7
7
  LONG_DESCRIPTION = DESCRIPTION
8
8
 
@@ -16,7 +16,7 @@ setup(
16
16
  long_description_content_type="text/markdown",
17
17
  long_description=open('README.md', encoding='utf-8').read(),
18
18
  packages=find_packages(),
19
- install_requires=["websocket-client","requests","bs4","SimpleWebSocketServer"],
19
+ install_requires=["websocket-client","requests","bs4","SimpleWebSocketServer", "typing-extensions"],
20
20
  keywords=['scratch api', 'scratchattach', 'scratch api python', 'scratch python', 'scratch for python', 'scratch', 'scratch cloud', 'scratch cloud variables', 'scratch bot'],
21
21
  url='https://scratchattach.tim1de.net',
22
22
  classifiers=[
@@ -0,0 +1,20 @@
1
+ exit()
2
+ import dotenv
3
+ dotenv.load_dotenv()
4
+ import scratchattach
5
+ import os
6
+
7
+ session_string = os.getenv("SCRATCH_SESSION_STRING")
8
+ assert session_string
9
+
10
+ session = scratchattach.login_by_session_string(session_string)
11
+
12
+ cloud = session.connect_cloud(693122627)
13
+ client = cloud.requests()
14
+
15
+ @client.request(name="get")
16
+ def get(user1, user2):
17
+ print(user1, user2, client.get_requester())
18
+ return "hi"
19
+
20
+ client.start()
File without changes
File without changes
File without changes