scratchattach 2.1.14__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.14.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.14.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 -306
  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 -825
  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.14.dist-info/RECORD +0 -66
  68. {scratchattach-2.1.14.dist-info → scratchattach-3.0.0b0.dist-info}/licenses/LICENSE +0 -0
  69. {scratchattach-2.1.14.dist-info → scratchattach-3.0.0b0.dist-info}/top_level.txt +0 -0
@@ -1,183 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import warnings
4
- from typing import Optional, TYPE_CHECKING
5
-
6
- from typing_extensions import deprecated
7
-
8
- if TYPE_CHECKING:
9
- from .block import Block
10
- from . import project
11
-
12
- from . import base
13
-
14
-
15
- class Monitor(base.ProjectSubcomponent):
16
- def __init__(self, reporter: Optional[base.NamedIDComponent] = None,
17
- mode: str = "default",
18
- opcode: str = "data_variable",
19
- params: Optional[dict] = None,
20
- sprite_name: Optional[str] = None,
21
- value=0,
22
- width: int | float = 0,
23
- height: int | float = 0,
24
- x: int | float = 5,
25
- y: int | float = 5,
26
- visible: bool = False,
27
- slider_min: int | float = 0,
28
- slider_max: int | float = 100,
29
- is_discrete: bool = True, *, reporter_id: Optional[str] = None, _project: Optional[project.Project] = None):
30
- """
31
- Represents a variable/list monitor
32
- https://en.scratch-wiki.info/wiki/Scratch_File_Format#Monitors
33
-
34
- Instantiating these yourself and attaching these to projects can lead to interesting results!
35
- """
36
- assert isinstance(reporter, base.SpriteSubComponent) or reporter is None
37
-
38
- self.reporter_id = reporter_id
39
- """
40
- ID referencing the VLB being referenced. Replaced with None during project instantiation, where the reporter attribute is updated
41
- """
42
-
43
- self.reporter = reporter
44
- if params is None:
45
- params = {}
46
-
47
- self.mode = mode
48
-
49
- self.opcode = opcode
50
- self.params = params
51
-
52
- self.sprite_name = sprite_name
53
-
54
- self.value = value
55
-
56
- self.width, self.height = width, height
57
- self.x, self.y = x, y
58
-
59
- self.visible = visible
60
-
61
- self.slider_min, self.slider_max = slider_min, slider_max
62
- self.is_discrete = is_discrete
63
-
64
- super().__init__(_project)
65
-
66
- def __repr__(self):
67
- return f"Monitor<{self.opcode}>"
68
-
69
- @property
70
- def id(self):
71
- if self.reporter is not None:
72
- return self.reporter.id
73
- # if isinstance(self.reporter, str):
74
- # return self.reporter
75
- # else:
76
- # return self.reporter.id
77
- else:
78
- return self.reporter_id
79
-
80
- @staticmethod
81
- def from_json(data: dict):
82
- _id = data["id"]
83
- # ^^ NEED TO FIND REPORTER OBJECT
84
-
85
- mode = data["mode"]
86
-
87
- opcode = data["opcode"]
88
- params: dict = data["params"]
89
-
90
- sprite_name = data["spriteName"]
91
-
92
- value = data["value"]
93
-
94
- width, height = data["width"], data["height"]
95
- x, y = data["x"], data["y"]
96
-
97
- visible = data["visible"]
98
-
99
- if "isDiscrete" in data.keys():
100
- slider_min, slider_max = data["sliderMin"], data["sliderMax"]
101
- is_discrete = data["isDiscrete"]
102
- else:
103
- slider_min, slider_max, is_discrete = None, None, None
104
-
105
- return Monitor(None, mode, opcode, params, sprite_name, value, width, height, x, y, visible, slider_min,
106
- slider_max, is_discrete, reporter_id=_id)
107
-
108
- def to_json(self):
109
- _json = {
110
- "id": self.id,
111
- "mode": self.mode,
112
-
113
- "opcode": self.opcode,
114
- "params": self.params,
115
-
116
- "spriteName": self.sprite_name,
117
-
118
- "value": self.value,
119
-
120
- "width": self.width,
121
- "height": self.height,
122
-
123
- "x": self.x,
124
- "y": self.y,
125
-
126
- "visible": self.visible
127
- }
128
- if self.is_discrete is not None:
129
- _json["sliderMin"] = self.slider_min
130
- _json["sliderMax"] = self.slider_max
131
- _json["isDiscrete"] = self.is_discrete
132
-
133
- return _json
134
-
135
- def link_using_project(self):
136
- assert self.project is not None
137
-
138
- if self.opcode in ("data_variable", "data_listcontents", "event_broadcast_menu"):
139
- new_vlb = self.project.find_vlb(self.reporter_id, "id")
140
- if new_vlb is not None:
141
- self.reporter = new_vlb
142
- self.reporter_id = None
143
-
144
- # todo: consider reimplementing this
145
- @deprecated("This method does not work correctly (This may be fixed in the future)")
146
- @staticmethod
147
- def from_reporter(reporter: "Block", _id: str = None, mode: str = "default",
148
- opcode: str = None, sprite_name: str = None, value=0, width: int | float = 0,
149
- height: int | float = 0,
150
- x: int | float = 5, y: int | float = 5, visible: bool = False, slider_min: int | float = 0,
151
- slider_max: int | float = 100, is_discrete: bool = True, params: dict = None):
152
- if "reporter" not in reporter.stack_type:
153
- warnings.warn(f"{reporter} is not a reporter block; the monitor will return '0'")
154
- elif "(menu)" in reporter.stack_type:
155
- warnings.warn(f"{reporter} is a menu block; the monitor will return '0'")
156
- # Maybe add note that length of list doesn't work fsr?? idk
157
- if _id is None:
158
- _id = reporter.opcode
159
- if opcode is None:
160
- opcode = reporter.opcode # .replace('_', ' ')
161
-
162
- if params is None:
163
- params = {}
164
- for field in reporter.fields:
165
- if field.value_id is None:
166
- params[field.id] = field.value
167
- else:
168
- params[field.id] = field.value, field.value_id
169
-
170
- return Monitor(
171
- _id,
172
- mode,
173
- opcode,
174
-
175
- params,
176
- sprite_name,
177
- value,
178
-
179
- width, height,
180
- x, y,
181
- visible,
182
- slider_min, slider_max, is_discrete
183
- )
@@ -1,324 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import warnings
5
- from dataclasses import dataclass
6
- from typing import Optional, TYPE_CHECKING, Iterable, Any
7
-
8
- from . import base, commons
9
- from scratchattach.utils import enums
10
-
11
- if TYPE_CHECKING:
12
- from . import block
13
-
14
-
15
- @dataclass
16
- class ArgumentType(base.Base):
17
- type: str
18
- proc_str: str
19
-
20
- def __eq__(self, other):
21
- if isinstance(other, enums._EnumWrapper):
22
- other = other.value
23
-
24
- assert isinstance(other, ArgumentType)
25
-
26
- return self.type == other.type
27
-
28
- def __repr__(self):
29
- return f"<ArgType {self.type!r}>"
30
-
31
- @property
32
- def default(self) -> str | None:
33
- if self.proc_str == "%b":
34
- return "false"
35
- elif self.proc_str == "%s":
36
- return ''
37
- else:
38
- return None
39
-
40
-
41
- @dataclass
42
- class ArgSettings(base.Base):
43
- ids: bool
44
- names: bool
45
- defaults: bool
46
-
47
- def __int__(self):
48
- return (int(self.ids) +
49
- int(self.names) +
50
- int(self.defaults))
51
-
52
- def __eq__(self, other):
53
- return (self.ids == other.ids and
54
- self.names == other.names and
55
- self.defaults == other.defaults)
56
-
57
- def __gt__(self, other):
58
- return int(self) > int(other)
59
-
60
- def __lt__(self, other):
61
- return int(self) > int(other)
62
-
63
-
64
- @dataclass
65
- class Argument(base.MutationSubComponent):
66
- name: str
67
- default: str = ''
68
-
69
- _id: str = None
70
- """
71
- Argument ID: Will be used to replace other parameters during block instantiation.
72
- """
73
-
74
- @property
75
- def index(self):
76
- return self.mutation.arguments.index(self)
77
-
78
- @property
79
- def type(self) -> None | ArgumentType:
80
- i = 0
81
- goal = self.index
82
- for token in parse_proc_code(self.mutation.proc_code):
83
- if isinstance(token, ArgumentType):
84
- if i == goal:
85
- return token
86
- i += 1
87
-
88
- @staticmethod
89
- def from_json(data: dict | list | Any):
90
- warnings.warn("No from_json method defined for Arguments (yet?)")
91
-
92
- def to_json(self) -> dict | list | Any:
93
- warnings.warn("No to_json method defined for Arguments (yet?)")
94
-
95
- def link_using_mutation(self):
96
- if self._id is None:
97
- self._id = self.block.new_id
98
-
99
-
100
- class ArgTypes(enums._EnumWrapper):
101
- BOOLEAN = ArgumentType("boolean", "%b")
102
- NUMBER_OR_TEXT = ArgumentType("number or text", "%s")
103
-
104
-
105
- def parse_proc_code(_proc_code: str) -> list[str, ArgumentType] | None:
106
- """
107
- Parse a proccode (part of a mutation) into argument types and strings
108
- """
109
-
110
- if _proc_code is None:
111
- return None
112
- token = ''
113
- tokens = []
114
-
115
- last_char = ''
116
- for char in _proc_code:
117
- if last_char == '%':
118
- if char in "sb":
119
- # If we've hit an %s or %b
120
- token = token[:-1]
121
- # Clip the % sign off the token
122
-
123
- if token != '':
124
- # Make sure not to append an empty token
125
- tokens.append(token)
126
-
127
- # Add the parameter token
128
- token = f"%{char}"
129
- if token == "%b":
130
- tokens.append(ArgTypes.BOOLEAN.value.dcopy())
131
- elif token == "%s":
132
- tokens.append(ArgTypes.NUMBER_OR_TEXT.value.dcopy())
133
-
134
- token = ''
135
- continue
136
-
137
- token += char
138
- last_char = char
139
-
140
- if token != '':
141
- tokens.append(token)
142
-
143
- return tokens
144
-
145
-
146
- class Mutation(base.BlockSubComponent):
147
- def __init__(self, _tag_name: str = "mutation", _children: Optional[list] = None, _proc_code: Optional[str] = None,
148
- _is_warp: Optional[bool] = None, _arguments: Optional[list[Argument]] = None, _has_next: Optional[bool] = None,
149
- _argument_settings: Optional[ArgSettings] = None, *,
150
- _block: Optional[block.Block] = None):
151
- """
152
- Mutation for Control:stop block and procedures
153
- https://en.scratch-wiki.info/wiki/Scratch_File_Format#Mutations
154
- """
155
- # Defaulting for args
156
- if _children is None:
157
- _children = []
158
-
159
- if _argument_settings is None:
160
- if _arguments:
161
- _argument_settings = ArgSettings(
162
- _arguments[0]._id is None,
163
- _arguments[0].name is None,
164
- _arguments[0].default is None
165
- )
166
- else:
167
- _argument_settings = ArgSettings(False, False, False)
168
-
169
- self.tag_name = _tag_name
170
- self.children = _children
171
-
172
- self.proc_code = _proc_code
173
- self.is_warp = _is_warp
174
- self.arguments = _arguments
175
- self.og_argument_settings = _argument_settings
176
-
177
- self.has_next = _has_next
178
-
179
- super().__init__(_block)
180
-
181
- def __repr__(self):
182
- if self.arguments is not None:
183
- return f"Mutation<args={self.arguments}>"
184
- else:
185
- return f"Mutation<hasnext={self.has_next}>"
186
-
187
- @property
188
- def argument_ids(self):
189
- if self.arguments is not None:
190
- return [_arg._id for _arg in self.arguments]
191
- else:
192
- return None
193
-
194
- @property
195
- def argument_names(self):
196
- if self.arguments is not None:
197
- return [_arg.name for _arg in self.arguments]
198
- else:
199
- return None
200
-
201
- @property
202
- def argument_defaults(self):
203
- if self.arguments is not None:
204
- return [_arg.default for _arg in self.arguments]
205
- else:
206
- return None
207
-
208
- @property
209
- def argument_settings(self) -> ArgSettings:
210
- return ArgSettings(bool(commons.safe_get(self.argument_ids, 0)),
211
- bool(commons.safe_get(self.argument_names, 0)),
212
- bool(commons.safe_get(self.argument_defaults, 0)))
213
-
214
- @property
215
- def parsed_proc_code(self) -> list[str, ArgumentType] | None:
216
- """
217
- Parse the proc code into arguments & strings
218
- """
219
- return parse_proc_code(self.proc_code)
220
-
221
- @staticmethod
222
- def from_json(data: dict) -> Mutation:
223
- assert isinstance(data, dict)
224
-
225
- _tag_name = data.get("tagName", "mutation")
226
- _children = data.get("children", [])
227
-
228
- # procedures_prototype & procedures_call attrs
229
- _proc_code = data.get("proccode")
230
- _is_warp = data.get("warp")
231
- if isinstance(_is_warp, str):
232
- _is_warp = json.loads(_is_warp)
233
-
234
- _argument_ids = data.get("argumentids")
235
- # For some reason these are stored as JSON strings
236
- if _argument_ids is not None:
237
- _argument_ids = json.loads(_argument_ids)
238
-
239
- # procedures_prototype attrs
240
- _argument_names = data.get("argumentnames")
241
- _argument_defaults = data.get("argumentdefaults")
242
- # For some reason these are stored as JSON strings
243
- if _argument_names is not None:
244
- assert isinstance(_argument_names, str)
245
- _argument_names = json.loads(_argument_names)
246
- if _argument_defaults is not None:
247
- assert isinstance(_argument_defaults, str)
248
- _argument_defaults = json.loads(_argument_defaults)
249
- _argument_settings = ArgSettings(_argument_ids is not None,
250
- _argument_names is not None,
251
- _argument_defaults is not None)
252
-
253
- # control_stop attrs
254
- _has_next = data.get("hasnext")
255
- if isinstance(_has_next, str):
256
- _has_next = json.loads(_has_next)
257
-
258
- def get(_lst: list | tuple | None, _idx: int):
259
- if _lst is None:
260
- return None
261
-
262
- if len(_lst) <= _idx:
263
- return None
264
- else:
265
- return _lst[_idx]
266
-
267
- if _argument_ids is None:
268
- _arguments = None
269
- else:
270
- _arguments = []
271
- for i, _arg_id in enumerate(_argument_ids):
272
- _arg_name = get(_argument_names, i)
273
- _arg_default = get(_argument_defaults, i)
274
-
275
- _arguments.append(Argument(_arg_name, _arg_default, _arg_id))
276
-
277
- return Mutation(_tag_name, _children, _proc_code, _is_warp, _arguments, _has_next, _argument_settings)
278
-
279
- def to_json(self) -> dict | None:
280
- _json = {
281
- "tagName": self.tag_name,
282
- "children": self.children,
283
- }
284
- commons.noneless_update(_json, {
285
- "proccode": self.proc_code,
286
- "warp": commons.dumps_ifnn(self.is_warp),
287
- "argumentids": commons.dumps_ifnn(self.argument_ids),
288
- "argumentnames": commons.dumps_ifnn(self.argument_names),
289
- "argumentdefaults": commons.dumps_ifnn(self.argument_defaults),
290
-
291
- "hasNext": commons.dumps_ifnn(self.has_next)
292
- })
293
-
294
- return _json
295
-
296
- def link_arguments(self):
297
- if self.arguments is None:
298
- return
299
-
300
- # You only need to fetch argument data if you actually have arguments
301
- if len(self.arguments) > 0:
302
- if self.arguments[0].name is None:
303
- # This requires linking
304
- _proc_uses = self.sprite.find_block(self.argument_ids, "argument ids", True)
305
- # Note: Sometimes there may not be any argument ids provided. There will be no way to find out the names
306
- # Technically, defaults can be found by using the proc code
307
- for _use in _proc_uses:
308
- if _use.mutation.argument_settings > self.argument_settings:
309
- self.arguments = _use.mutation.arguments
310
- if int(self.argument_settings) == 3:
311
- # If all of our argument data is filled, we can stop early
312
- return
313
-
314
- # We can still work out argument defaults from parsing the proc code
315
- if self.arguments[0].default is None:
316
- _parsed = self.parsed_proc_code
317
- _arg_phs: Iterable[ArgumentType] = filter(lambda tkn: isinstance(tkn, ArgumentType),
318
- _parsed)
319
- for i, _arg_ph in enumerate(_arg_phs):
320
- self.arguments[i].default = _arg_ph.default
321
-
322
- for _argument in self.arguments:
323
- _argument.mutation = self
324
- _argument.link_using_mutation()
@@ -1,90 +0,0 @@
1
- """
2
- Collection of block information, stating input/field names and opcodes
3
- New version of sbuild.py
4
-
5
- May want to completely change this later
6
- """
7
- from __future__ import annotations
8
-
9
- from dataclasses import dataclass, field
10
- from typing import Optional
11
-
12
- from . import prim
13
- from scratchattach.utils.enums import _EnumWrapper
14
-
15
-
16
- @dataclass
17
- class FieldUsage:
18
- name: str
19
- value_type: Optional[prim.PrimTypes] = None
20
-
21
-
22
- @dataclass
23
- class SpecialFieldUsage(FieldUsage):
24
- name: str
25
- value_type: None = None # Order cannot be changed
26
- attrs: list[str] = field(default_factory=list)
27
-
28
-
29
-
30
- @dataclass
31
- class InputUsage:
32
- name: str
33
- value_type: Optional[prim.PrimTypes] = None
34
- default_obscurer: Optional[BlockUsage] = None
35
-
36
-
37
- @dataclass
38
- class BlockUsage:
39
- opcode: str
40
- fields: Optional[list[FieldUsage]] = None
41
- if fields is None:
42
- fields = []
43
-
44
- inputs: Optional[list[InputUsage]] = None
45
- if inputs is None:
46
- inputs = []
47
-
48
-
49
- class BlockUsages(_EnumWrapper):
50
- # Special Enum blocks
51
- MATH_NUMBER = BlockUsage(
52
- "math_number",
53
- [SpecialFieldUsage("NUM", attrs=["name", "value"])]
54
- )
55
- MATH_POSITIVE_NUMBER = BlockUsage(
56
- "math_positive_number",
57
- [SpecialFieldUsage("NUM", attrs=["name", "value"])]
58
- )
59
- MATH_WHOLE_NUMBER = BlockUsage(
60
- "math_whole_number",
61
- [SpecialFieldUsage("NUM", attrs=["name", "value"])]
62
- )
63
- MATH_INTEGER = BlockUsage(
64
- "math_integer",
65
- [SpecialFieldUsage("NUM", attrs=["name", "value"])]
66
- )
67
- MATH_ANGLE = BlockUsage(
68
- "math_angle",
69
- [SpecialFieldUsage("NUM", attrs=["name", "value"])]
70
- )
71
- COLOUR_PICKER = BlockUsage(
72
- "colour_picker",
73
- [SpecialFieldUsage("COLOUR", attrs=["name", "value"])]
74
- )
75
- TEXT = BlockUsage(
76
- "text",
77
- [SpecialFieldUsage("TEXT", attrs=["name", "value"])]
78
- )
79
- EVENT_BROADCAST_MENU = BlockUsage(
80
- "event_broadcast_menu",
81
- [SpecialFieldUsage("BROADCAST_OPTION", attrs=["name", "id", "value", "variableType"])]
82
- )
83
- DATA_VARIABLE = BlockUsage(
84
- "data_variable",
85
- [SpecialFieldUsage("VARIABLE", attrs=["name", "id", "value", "variableType"])]
86
- )
87
- DATA_LISTCONTENTS = BlockUsage(
88
- "data_listcontents",
89
- [SpecialFieldUsage("LIST", attrs=["name", "id", "value", "variableType"])]
90
- )