scratchattach 2.1.15b0__py3-none-any.whl → 3.0.0b0__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 (69) hide show
  1. scratchattach/__init__.py +14 -6
  2. scratchattach/__main__.py +93 -0
  3. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/METADATA +7 -11
  4. scratchattach-3.0.0b0.dist-info/RECORD +8 -0
  5. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/WHEEL +1 -1
  6. scratchattach-3.0.0b0.dist-info/entry_points.txt +2 -0
  7. scratchattach/cloud/__init__.py +0 -2
  8. scratchattach/cloud/_base.py +0 -458
  9. scratchattach/cloud/cloud.py +0 -183
  10. scratchattach/editor/__init__.py +0 -21
  11. scratchattach/editor/asset.py +0 -253
  12. scratchattach/editor/backpack_json.py +0 -117
  13. scratchattach/editor/base.py +0 -193
  14. scratchattach/editor/block.py +0 -579
  15. scratchattach/editor/blockshape.py +0 -357
  16. scratchattach/editor/build_defaulting.py +0 -51
  17. scratchattach/editor/code_translation/__init__.py +0 -0
  18. scratchattach/editor/code_translation/parse.py +0 -177
  19. scratchattach/editor/comment.py +0 -80
  20. scratchattach/editor/commons.py +0 -273
  21. scratchattach/editor/extension.py +0 -50
  22. scratchattach/editor/field.py +0 -99
  23. scratchattach/editor/inputs.py +0 -135
  24. scratchattach/editor/meta.py +0 -114
  25. scratchattach/editor/monitor.py +0 -183
  26. scratchattach/editor/mutation.py +0 -324
  27. scratchattach/editor/pallete.py +0 -90
  28. scratchattach/editor/prim.py +0 -170
  29. scratchattach/editor/project.py +0 -279
  30. scratchattach/editor/sprite.py +0 -599
  31. scratchattach/editor/twconfig.py +0 -114
  32. scratchattach/editor/vlb.py +0 -134
  33. scratchattach/eventhandlers/__init__.py +0 -0
  34. scratchattach/eventhandlers/_base.py +0 -100
  35. scratchattach/eventhandlers/cloud_events.py +0 -110
  36. scratchattach/eventhandlers/cloud_recorder.py +0 -26
  37. scratchattach/eventhandlers/cloud_requests.py +0 -459
  38. scratchattach/eventhandlers/cloud_server.py +0 -246
  39. scratchattach/eventhandlers/cloud_storage.py +0 -136
  40. scratchattach/eventhandlers/combine.py +0 -30
  41. scratchattach/eventhandlers/filterbot.py +0 -161
  42. scratchattach/eventhandlers/message_events.py +0 -42
  43. scratchattach/other/__init__.py +0 -0
  44. scratchattach/other/other_apis.py +0 -284
  45. scratchattach/other/project_json_capabilities.py +0 -475
  46. scratchattach/site/__init__.py +0 -0
  47. scratchattach/site/_base.py +0 -66
  48. scratchattach/site/activity.py +0 -382
  49. scratchattach/site/alert.py +0 -227
  50. scratchattach/site/backpack_asset.py +0 -118
  51. scratchattach/site/browser_cookie3_stub.py +0 -17
  52. scratchattach/site/browser_cookies.py +0 -61
  53. scratchattach/site/classroom.py +0 -447
  54. scratchattach/site/cloud_activity.py +0 -107
  55. scratchattach/site/comment.py +0 -242
  56. scratchattach/site/forum.py +0 -432
  57. scratchattach/site/project.py +0 -826
  58. scratchattach/site/session.py +0 -1238
  59. scratchattach/site/studio.py +0 -611
  60. scratchattach/site/user.py +0 -956
  61. scratchattach/utils/__init__.py +0 -0
  62. scratchattach/utils/commons.py +0 -255
  63. scratchattach/utils/encoder.py +0 -158
  64. scratchattach/utils/enums.py +0 -236
  65. scratchattach/utils/exceptions.py +0 -243
  66. scratchattach/utils/requests.py +0 -93
  67. scratchattach-2.1.15b0.dist-info/RECORD +0 -66
  68. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/licenses/LICENSE +0 -0
  69. {scratchattach-2.1.15b0.dist-info → scratchattach-3.0.0b0.dist-info}/top_level.txt +0 -0
@@ -1,134 +0,0 @@
1
- """
2
- Variables, lists & broadcasts
3
- """
4
- # Perhaps ids should not be stored in these objects, but in the sprite, similarly
5
- # to how blocks/prims are stored
6
-
7
- from __future__ import annotations
8
-
9
- from typing import Optional, Literal
10
-
11
- from . import base, sprite, build_defaulting
12
- from scratchattach.utils import exceptions
13
-
14
-
15
- class Variable(base.NamedIDComponent):
16
- def __init__(self, _id: str, _name: str, _value: Optional[str | int | float] = None, _is_cloud: bool = False,
17
- _sprite: sprite.Sprite = build_defaulting.SPRITE_DEFAULT):
18
- """
19
- Class representing a variable.
20
- https://en.scratch-wiki.info/wiki/Scratch_File_Format#Targets:~:text=variables,otherwise%20not%20present
21
- """
22
- if _value is None:
23
- _value = 0
24
-
25
- self.value = _value
26
- self.is_cloud = _is_cloud
27
-
28
- super().__init__(_id, _name, _sprite)
29
-
30
- @property
31
- def is_global(self):
32
- """
33
- Works out whethere a variable is global based on whether the sprite is a stage
34
- :return: Whether this variable is a global variable.
35
- """
36
- return self.sprite.is_stage
37
-
38
- @staticmethod
39
- def from_json(data: tuple[str, tuple[str, str | int | float] | tuple[str, str | int | float, bool]]):
40
- """
41
- Read data in format: (variable id, variable JSON)
42
- """
43
- assert len(data) == 2
44
- _id, data = data
45
-
46
- assert len(data) in (2, 3)
47
- _name, _value = data[:2]
48
-
49
- if len(data) == 3:
50
- _is_cloud = data[2]
51
- else:
52
- _is_cloud = False
53
-
54
- return Variable(_id, _name, _value, _is_cloud)
55
-
56
- def to_json(self) -> tuple[str, str | int | float, bool] | tuple[str, str | int | float]:
57
- """
58
- Returns Variable data as a tuple
59
- """
60
- if self.is_cloud:
61
- _ret = self.name, self.value, True
62
- else:
63
- _ret = self.name, self.value
64
-
65
- return _ret
66
-
67
-
68
- class List(base.NamedIDComponent):
69
- def __init__(self, _id: str, _name: str, _value: Optional[list[str | int | float]] = None,
70
- _sprite: sprite.Sprite = build_defaulting.SPRITE_DEFAULT):
71
- """
72
- Class representing a list.
73
- https://en.scratch-wiki.info/wiki/Scratch_File_Format#Targets:~:text=lists,as%20an%20array
74
- """
75
- if _value is None:
76
- _value = []
77
-
78
- self.value = _value
79
- super().__init__(_id, _name, _sprite)
80
-
81
- @staticmethod
82
- def from_json(data: tuple[str, tuple[str, str | int | float] | tuple[str, str | int | float, bool]]):
83
- """
84
- Read data in format: (variable id, variable JSON)
85
- """
86
- assert len(data) == 2
87
- _id, data = data
88
-
89
- assert len(data) == 2
90
- _name, _value = data
91
-
92
- return List(_id, _name, _value)
93
-
94
- def to_json(self) -> tuple[str, tuple[str, str | int | float, bool] | tuple[str, str | int | float]]:
95
- """
96
- Returns List data as a tuple
97
- """
98
- return self.name, self.value
99
-
100
-
101
- class Broadcast(base.NamedIDComponent):
102
- def __init__(self, _id: str, _name: str, _sprite: sprite.Sprite = build_defaulting.SPRITE_DEFAULT):
103
- """
104
- Class representing a broadcast.
105
- https://en.scratch-wiki.info/wiki/Scratch_File_Format#Targets:~:text=broadcasts,in%20the%20stage
106
- """
107
- super().__init__(_id, _name, _sprite)
108
-
109
- @staticmethod
110
- def from_json(data: tuple[str, str]):
111
- assert len(data) == 2
112
- _id, _name = data
113
-
114
- return Broadcast(_id, _name)
115
-
116
- def to_json(self) -> str:
117
- """
118
- :return: Broadcast as JSON (just a string of its name)
119
- """
120
- return self.name
121
-
122
-
123
- def construct(vlb_type: Literal["variable", "list", "broadcast"], _id: Optional[str] = None, _name: Optional[str] = None,
124
- _sprite: sprite.Sprite = build_defaulting.SPRITE_DEFAULT) -> Variable | List | Broadcast:
125
- if vlb_type == "variable":
126
- vlb_type = Variable
127
- elif vlb_type == "list":
128
- vlb_type = List
129
- elif vlb_type == "broadcast":
130
- vlb_type = Broadcast
131
- else:
132
- raise exceptions.InvalidVLBName(f"Bad VLB {vlb_type!r}")
133
-
134
- return vlb_type(_id, _name, _sprite)
File without changes
@@ -1,100 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from abc import ABC, abstractmethod
4
- from collections import defaultdict
5
- from threading import Thread
6
- from collections.abc import Callable
7
- import traceback
8
- from scratchattach.utils.requests import requests
9
- from scratchattach.utils import exceptions
10
-
11
- class BaseEventHandler(ABC):
12
- _events: defaultdict[str, list[Callable]]
13
- _threaded_events: defaultdict[str, list[Callable]]
14
-
15
- def __init__(self):
16
- self._thread = None
17
- self.running = False
18
- self._events = defaultdict(list)
19
- self._threaded_events = defaultdict(list)
20
-
21
- def start(self, *, thread=True, ignore_exceptions=True):
22
- """
23
- Starts the event handler.
24
-
25
- Keyword Arguments:
26
- thread (bool): Whether the event handler should be run in a thread.
27
- ignore_exceptions (bool): Whether to catch exceptions that happen in individual events
28
- """
29
- if self.running is False:
30
- self.ignore_exceptions = ignore_exceptions
31
- self.running = True
32
- if thread:
33
- self._thread = Thread(target=self._updater, args=())
34
- self._thread.start()
35
- else:
36
- self._thread = None
37
- self._updater()
38
-
39
- def call_event(self, event_name, args : list = []):
40
- try:
41
- if event_name in self._threaded_events:
42
- for func in self._threaded_events[event_name]:
43
- Thread(target=func, args=args).start()
44
- if event_name in self._events:
45
- for func in self._events[event_name]:
46
- func(*args)
47
- except Exception as e:
48
- if self.ignore_exceptions:
49
- print(
50
- f"Warning: Caught error in event '{event_name}' - Full error below"
51
- )
52
- try:
53
- traceback.print_exc()
54
- except Exception:
55
- print(e)
56
- else:
57
- raise(e)
58
-
59
- @abstractmethod
60
- def _updater(self):
61
- pass
62
-
63
- def stop(self):
64
- """
65
- Permanently stops the event handler.
66
- """
67
- self.running = False
68
- if self._thread is not None:
69
- self._thread = None
70
-
71
- def pause(self):
72
- """
73
- Pauses the event handler.
74
- """
75
- self.running = False
76
-
77
- def resume(self):
78
- """
79
- Resumes the event handler.
80
- """
81
- if self.running is False:
82
- self.start()
83
-
84
- def event(self, function=None, *, thread=False):
85
- """
86
- Decorator function. Adds an event.
87
- """
88
- def inner(function):
89
- # called directly if the decorator provides arguments
90
- if thread is True:
91
- self._threaded_events[function.__name__].append(function)
92
- else:
93
- self._events[function.__name__].append(function)
94
-
95
- if function is None:
96
- # => the decorator provides arguments
97
- return inner
98
- else:
99
- # => the decorator doesn't provide arguments
100
- inner(function)
@@ -1,110 +0,0 @@
1
- """CloudEvents class"""
2
- from __future__ import annotations
3
-
4
- from scratchattach.cloud import _base
5
- from ._base import BaseEventHandler
6
- from scratchattach.site import cloud_activity
7
- import time
8
- import json
9
- from collections.abc import Iterator
10
-
11
- class CloudEvents(BaseEventHandler):
12
- """
13
- Class that calls events when on cloud updates that are received through a websocket connection.
14
- """
15
- def __init__(self, cloud: _base.AnyCloud):
16
- super().__init__()
17
- self.cloud = cloud
18
- self._session = cloud._session
19
- self.source_stream = cloud.create_event_stream()
20
- self.startup_time = time.time() * 1000
21
-
22
- def disconnect(self):
23
- self.source_stream.close()
24
-
25
- def _updater(self):
26
- """
27
- A process that listens for cloud activity and executes events on cloud activity
28
- """
29
-
30
- self.call_event("on_ready")
31
-
32
- if self.running is False:
33
- return
34
- while True:
35
- try:
36
- while True:
37
- for data in self.source_stream.read():
38
- try:
39
- _a = cloud_activity.CloudActivity(timestamp=time.time()*1000, _session=self._session, cloud=self.cloud)
40
- if _a.timestamp < self.startup_time + 500: # catch the on_connect message sent by TurboWarp's (and sometimes Scratch's) cloud server
41
- continue
42
- data["variable_name"] = data["name"]
43
- data["name"] = data["variable_name"].replace("☁ ", "")
44
- _a._update_from_dict(data)
45
- self.call_event("on_"+_a.type, [_a])
46
- except Exception as e:
47
- pass
48
- except Exception:
49
- print("CloudEvents: Disconnected. Reconnecting ...", time.time())
50
- time.sleep(0.1) # cooldown
51
-
52
- print("CloudEvents: Reconnected.", time.time())
53
- self.call_event("on_reconnect", [])
54
-
55
- class ManualCloudLogEvents:
56
- """
57
- Class that calls events on cloud updates that are received from a clouddata log.
58
- """
59
- def __init__(self, cloud: _base.LogCloud):
60
- if not isinstance(cloud, _base.LogCloud):
61
- raise ValueError("Cloud log events can't be used with a cloud that has no logs available")
62
- self.cloud = cloud
63
- self.source_cloud = cloud
64
- self._session = cloud._session
65
- self.last_timestamp = 0
66
-
67
- def update(self) -> Iterator[tuple[str, list[cloud_activity.CloudActivity]]]:
68
- """
69
- Update once and yield all packets
70
- """
71
- try:
72
- data = self.source_cloud.logs(limit=25)
73
- for _a in data[::-1]:
74
- if _a.timestamp <= self.last_timestamp:
75
- continue
76
- self.last_timestamp = _a.timestamp
77
- yield ("on_"+_a.type, [_a])
78
- except Exception:
79
- pass
80
-
81
-
82
- class CloudLogEvents(BaseEventHandler):
83
- """
84
- Class that calls events on cloud updates that are received from a clouddata log.
85
- """
86
- def __init__(self, cloud: _base.LogCloud, *, update_interval=0.1):
87
- super().__init__()
88
- if not isinstance(cloud, _base.LogCloud):
89
- raise ValueError("Cloud log events can't be used with a cloud that has no logs available")
90
- self.cloud = cloud
91
- self.source_cloud = cloud
92
- self.update_interval = update_interval
93
- self._session = cloud._session
94
- self.last_timestamp = 0
95
- self.manual_cloud_log_events = ManualCloudLogEvents(cloud)
96
-
97
- def _updater(self):
98
- logs = self.source_cloud.logs(limit=25)
99
- self.last_timestamp = 0
100
- if len(logs) != 0:
101
- self.last_timestamp = logs[0].timestamp
102
-
103
- self.call_event("on_ready")
104
-
105
- while True:
106
- if self.running is False:
107
- return
108
- for event_type, event_data in self.manual_cloud_log_events.update():
109
- self.call_event(event_type, event_data)
110
- time.sleep(self.update_interval)
@@ -1,26 +0,0 @@
1
- """CloudRecorder class (used by ScratchCloud, TwCloud and other classes inheriting from BaseCloud to deliver cloud var values)"""
2
- from __future__ import annotations
3
-
4
- from .cloud_events import CloudEvents
5
- from typing import Optional
6
-
7
-
8
- class CloudRecorder(CloudEvents):
9
- def __init__(self, cloud, *, initial_values: Optional[dict] = None):
10
- if initial_values is None:
11
- initial_values = {}
12
-
13
- super().__init__(cloud)
14
- self.cloud_values = initial_values
15
- self.event(self.on_set)
16
-
17
- def get_var(self, var):
18
- if var not in self.cloud_values:
19
- return None
20
- return self.cloud_values[var]
21
-
22
- def get_all_vars(self):
23
- return self.cloud_values
24
-
25
- def on_set(self, activity):
26
- self.cloud_values[activity.var] = activity.value