scratchattach 3.0.0b0__py3-none-any.whl → 3.0.0b2__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 (80) hide show
  1. scratchattach/cli/__about__.py +1 -0
  2. scratchattach/cli/__init__.py +26 -0
  3. scratchattach/cli/cmd/__init__.py +4 -0
  4. scratchattach/cli/cmd/group.py +127 -0
  5. scratchattach/cli/cmd/login.py +60 -0
  6. scratchattach/cli/cmd/profile.py +7 -0
  7. scratchattach/cli/cmd/sessions.py +5 -0
  8. scratchattach/cli/context.py +142 -0
  9. scratchattach/cli/db.py +66 -0
  10. scratchattach/cli/namespace.py +14 -0
  11. scratchattach/cloud/__init__.py +2 -0
  12. scratchattach/cloud/_base.py +483 -0
  13. scratchattach/cloud/cloud.py +183 -0
  14. scratchattach/editor/__init__.py +22 -0
  15. scratchattach/editor/asset.py +265 -0
  16. scratchattach/editor/backpack_json.py +115 -0
  17. scratchattach/editor/base.py +191 -0
  18. scratchattach/editor/block.py +584 -0
  19. scratchattach/editor/blockshape.py +357 -0
  20. scratchattach/editor/build_defaulting.py +51 -0
  21. scratchattach/editor/code_translation/__init__.py +0 -0
  22. scratchattach/editor/code_translation/parse.py +177 -0
  23. scratchattach/editor/comment.py +80 -0
  24. scratchattach/editor/commons.py +145 -0
  25. scratchattach/editor/extension.py +50 -0
  26. scratchattach/editor/field.py +99 -0
  27. scratchattach/editor/inputs.py +138 -0
  28. scratchattach/editor/meta.py +117 -0
  29. scratchattach/editor/monitor.py +185 -0
  30. scratchattach/editor/mutation.py +381 -0
  31. scratchattach/editor/pallete.py +88 -0
  32. scratchattach/editor/prim.py +174 -0
  33. scratchattach/editor/project.py +381 -0
  34. scratchattach/editor/sprite.py +609 -0
  35. scratchattach/editor/twconfig.py +114 -0
  36. scratchattach/editor/vlb.py +134 -0
  37. scratchattach/eventhandlers/__init__.py +0 -0
  38. scratchattach/eventhandlers/_base.py +101 -0
  39. scratchattach/eventhandlers/cloud_events.py +130 -0
  40. scratchattach/eventhandlers/cloud_recorder.py +26 -0
  41. scratchattach/eventhandlers/cloud_requests.py +544 -0
  42. scratchattach/eventhandlers/cloud_server.py +249 -0
  43. scratchattach/eventhandlers/cloud_storage.py +135 -0
  44. scratchattach/eventhandlers/combine.py +30 -0
  45. scratchattach/eventhandlers/filterbot.py +163 -0
  46. scratchattach/eventhandlers/message_events.py +42 -0
  47. scratchattach/other/__init__.py +0 -0
  48. scratchattach/other/other_apis.py +598 -0
  49. scratchattach/other/project_json_capabilities.py +475 -0
  50. scratchattach/site/__init__.py +0 -0
  51. scratchattach/site/_base.py +93 -0
  52. scratchattach/site/activity.py +426 -0
  53. scratchattach/site/alert.py +226 -0
  54. scratchattach/site/backpack_asset.py +119 -0
  55. scratchattach/site/browser_cookie3_stub.py +17 -0
  56. scratchattach/site/browser_cookies.py +61 -0
  57. scratchattach/site/classroom.py +454 -0
  58. scratchattach/site/cloud_activity.py +121 -0
  59. scratchattach/site/comment.py +228 -0
  60. scratchattach/site/forum.py +436 -0
  61. scratchattach/site/placeholder.py +132 -0
  62. scratchattach/site/project.py +932 -0
  63. scratchattach/site/session.py +1323 -0
  64. scratchattach/site/studio.py +704 -0
  65. scratchattach/site/typed_dicts.py +151 -0
  66. scratchattach/site/user.py +1252 -0
  67. scratchattach/utils/__init__.py +0 -0
  68. scratchattach/utils/commons.py +263 -0
  69. scratchattach/utils/encoder.py +161 -0
  70. scratchattach/utils/enums.py +237 -0
  71. scratchattach/utils/exceptions.py +277 -0
  72. scratchattach/utils/optional_async.py +154 -0
  73. scratchattach/utils/requests.py +306 -0
  74. {scratchattach-3.0.0b0.dist-info → scratchattach-3.0.0b2.dist-info}/METADATA +1 -1
  75. scratchattach-3.0.0b2.dist-info/RECORD +81 -0
  76. scratchattach-3.0.0b0.dist-info/RECORD +0 -8
  77. {scratchattach-3.0.0b0.dist-info → scratchattach-3.0.0b2.dist-info}/WHEEL +0 -0
  78. {scratchattach-3.0.0b0.dist-info → scratchattach-3.0.0b2.dist-info}/entry_points.txt +0 -0
  79. {scratchattach-3.0.0b0.dist-info → scratchattach-3.0.0b2.dist-info}/licenses/LICENSE +0 -0
  80. {scratchattach-3.0.0b0.dist-info → scratchattach-3.0.0b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,357 @@
1
+ """
2
+ Enums stating the shape of a block from its opcode (i.e: stack, c-mouth, cap, hat etc)
3
+ """
4
+ from __future__ import annotations
5
+
6
+ # Perhaps this should be merged with pallete.py
7
+ from dataclasses import dataclass
8
+ from typing import Final, Literal
9
+
10
+ from . import commons
11
+ from scratchattach.utils.enums import _EnumWrapper
12
+
13
+
14
+ class _MutationDependent(commons.Singleton):
15
+ """
16
+ Singleton value that represents the uncertainty of a vablue because it depends on block mutation data.
17
+ """
18
+ INSTANCE = 0
19
+ def __bool__(self):
20
+ raise TypeError("Need mutation data to work out attribute value.")
21
+
22
+
23
+ MUTATION_DEPENDENT: Final[Literal[_MutationDependent.INSTANCE]] = _MutationDependent.INSTANCE
24
+ """Value used when mutation data is required to work out the attribute value"""
25
+
26
+
27
+ @dataclass(init=True, repr=True)
28
+ class BlockShape:
29
+ """
30
+ The shape of a block; e.g. is it a stack, c-mouth, cap, hat reporter, boolean or menu block?
31
+ """
32
+ is_stack: bool | _MutationDependent = False # Most blocks - e.g. move [10] steps
33
+ is_c_mouth: bool | _MutationDependent = False # Has substack - e.g. repeat
34
+ is_cap: bool | _MutationDependent = False # No next - e.g. forever
35
+ is_hat: bool | _MutationDependent = False # No parent - e.g. when gf clicked
36
+ is_reporter: bool | _MutationDependent = False # (reporter)
37
+ is_boolean: bool | _MutationDependent = False # <reporter>
38
+ is_menu: bool | _MutationDependent = False # Shadow reporters, e.g. costume menu
39
+ opcode: str = None
40
+
41
+ @property
42
+ def is_attachable(self):
43
+ if self.is_cap is MUTATION_DEPENDENT:
44
+ raise TypeError(
45
+ "Can't tell if the block is attachable because we can't be sure if it is a cap block or not (stop block)")
46
+ return not self.is_cap and not self.is_reporter
47
+
48
+
49
+ class BlockShapes(_EnumWrapper):
50
+ MOTION_MOVESTEPS = BlockShape(is_stack=True, opcode="motion_movesteps")
51
+ MOTION_TURNRIGHT = BlockShape(is_stack=True, opcode="motion_turnright")
52
+ MOTION_TURNLEFT = BlockShape(is_stack=True, opcode="motion_turnleft")
53
+ MOTION_GOTO = BlockShape(is_stack=True, opcode="motion_goto")
54
+ MOTION_GOTOXY = BlockShape(is_stack=True, opcode="motion_gotoxy")
55
+ MOTION_GLIDETO = BlockShape(is_stack=True, opcode="motion_glideto")
56
+ MOTION_GLIDESECSTOXY = BlockShape(is_stack=True, opcode="motion_glidesecstoxy")
57
+ MOTION_POINTINDIRECTION = BlockShape(is_stack=True, opcode="motion_pointindirection")
58
+ MOTION_POINTTOWARDS = BlockShape(is_stack=True, opcode="motion_pointtowards")
59
+ MOTION_CHANGEXBY = BlockShape(is_stack=True, opcode="motion_changexby")
60
+ MOTION_SETX = BlockShape(is_stack=True, opcode="motion_setx")
61
+ MOTION_CHANGEYBY = BlockShape(is_stack=True, opcode="motion_changeyby")
62
+ MOTION_SETY = BlockShape(is_stack=True, opcode="motion_sety")
63
+ MOTION_IFONEDGEBOUNCE = BlockShape(is_stack=True, opcode="motion_ifonedgebounce")
64
+ MOTION_SETROTATIONSTYLE = BlockShape(is_stack=True, opcode="motion_setrotationstyle")
65
+ MOTION_XPOSITION = BlockShape(is_reporter=True, opcode="motion_xposition")
66
+ MOTION_YPOSITION = BlockShape(is_reporter=True, opcode="motion_yposition")
67
+ MOTION_DIRECTION = BlockShape(is_reporter=True, opcode="motion_direction")
68
+ MOTION_SCROLL_RIGHT = BlockShape(is_stack=True, opcode="motion_scroll_right")
69
+ MOTION_SCROLL_UP = BlockShape(is_stack=True, opcode="motion_scroll_up")
70
+ MOTION_ALIGN_SCENE = BlockShape(is_stack=True, opcode="motion_align_scene")
71
+ MOTION_XSCROLL = BlockShape(is_reporter=True, opcode="motion_xscroll")
72
+ MOTION_YSCROLL = BlockShape(is_reporter=True, opcode="motion_yscroll")
73
+ MOTION_GOTO_MENU = BlockShape(is_reporter=True, is_menu=True, opcode="motion_goto_menu")
74
+ MOTION_GLIDETO_MENU = BlockShape(is_reporter=True, is_menu=True, opcode="motion_glideto_menu")
75
+ MOTION_POINTTOWARDS_MENU = BlockShape(is_reporter=True, is_menu=True, opcode="motion_pointtowards_menu")
76
+
77
+ LOOKS_SAYFORSECS = BlockShape(is_stack=True, opcode="looks_sayforsecs")
78
+ LOOKS_SAY = BlockShape(is_stack=True, opcode="looks_say")
79
+ LOOKS_THINKFORSECS = BlockShape(is_stack=True, opcode="looks_thinkforsecs")
80
+ LOOKS_THINK = BlockShape(is_stack=True, opcode="looks_think")
81
+ LOOKS_SWITCHCOSTUMETO = BlockShape(is_stack=True, opcode="looks_switchcostumeto")
82
+ LOOKS_NEXTCOSTUME = BlockShape(is_stack=True, opcode="looks_nextcostume")
83
+ LOOKS_SWITCHBACKDROPTO = BlockShape(is_stack=True, opcode="looks_switchbackdropto")
84
+ LOOKS_SWITCHBACKDROPTOANDWAIT = BlockShape(is_stack=True, opcode="looks_switchbackdroptoandwait")
85
+ LOOKS_NEXTBACKDROP = BlockShape(is_stack=True, opcode="looks_nextbackdrop")
86
+ LOOKS_CHANGESIZEBY = BlockShape(is_stack=True, opcode="looks_changesizeby")
87
+ LOOKS_SETSIZETO = BlockShape(is_stack=True, opcode="looks_setsizeto")
88
+ LOOKS_CHANGEEFFECTBY = BlockShape(is_stack=True, opcode="looks_changeeffectby")
89
+ LOOKS_SETEFFECTTO = BlockShape(is_stack=True, opcode="looks_seteffectto")
90
+ LOOKS_CLEARGRAPHICEFFECTS = BlockShape(is_stack=True, opcode="looks_cleargraphiceffects")
91
+ LOOKS_SHOW = BlockShape(is_stack=True, opcode="looks_show")
92
+ LOOKS_HIDE = BlockShape(is_stack=True, opcode="looks_hide")
93
+ LOOKS_GOTOFRONTBACK = BlockShape(is_stack=True, opcode="looks_gotofrontback")
94
+ LOOKS_GOFORWARDBACKWARDLAYERS = BlockShape(is_stack=True, opcode="looks_goforwardbackwardlayers")
95
+ LOOKS_COSTUMENUMBERNAME = BlockShape(is_reporter=True, opcode="looks_costumenumbername")
96
+ LOOKS_BACKDROPNUMBERNAME = BlockShape(is_reporter=True, opcode="looks_backdropnumbername")
97
+ LOOKS_SIZE = BlockShape(is_reporter=True, opcode="looks_size")
98
+ LOOKS_HIDEALLSPRITES = BlockShape(is_stack=True, opcode="looks_hideallsprites")
99
+ LOOKS_SETSTRETCHTO = BlockShape(is_stack=True, opcode="looks_setstretchto")
100
+ LOOKS_CHANGESTRETCHBY = BlockShape(is_stack=True, opcode="looks_changestretchby")
101
+ LOOKS_COSTUME = BlockShape(is_reporter=True, is_menu=True, opcode="looks_costume")
102
+ LOOKS_BACKDROPS = BlockShape(is_reporter=True, is_menu=True, opcode="looks_backdrops")
103
+
104
+ SOUND_PLAYUNTILDONE = BlockShape(is_stack=True, opcode="sound_playuntildone")
105
+ SOUND_PLAY = BlockShape(is_stack=True, opcode="sound_play")
106
+ SOUND_STOPALLSOUNDS = BlockShape(is_stack=True, opcode="sound_stopallsounds")
107
+ SOUND_CHANGEEFFECTBY = BlockShape(is_stack=True, opcode="sound_changeeffectby")
108
+ SOUND_SETEFFECTTO = BlockShape(is_stack=True, opcode="sound_seteffectto")
109
+ SOUND_CLEAREFFECTS = BlockShape(is_stack=True, opcode="sound_cleareffects")
110
+ SOUND_CHANGEVOLUMEBY = BlockShape(is_stack=True, opcode="sound_changevolumeby")
111
+ SOUND_SETVOLUMETO = BlockShape(is_stack=True, opcode="sound_setvolumeto")
112
+ SOUND_VOLUME = BlockShape(is_reporter=True, opcode="sound_volume")
113
+ SOUND_SOUNDS_MENU = BlockShape(is_reporter=True, is_menu=True, opcode="sound_sounds_menu")
114
+
115
+ EVENT_WHENFLAGCLICKED = BlockShape(is_hat=True, opcode="event_whenflagclicked")
116
+ EVENT_WHENKEYPRESSED = BlockShape(is_hat=True, opcode="event_whenkeypressed")
117
+ EVENT_WHENTHISSPRITECLICKED = BlockShape(is_hat=True, opcode="event_whenthisspriteclicked")
118
+ EVENT_WHENSTAGECLICKED = BlockShape(is_hat=True, opcode="event_whenstageclicked")
119
+ EVENT_WHENBACKDROPSWITCHESTO = BlockShape(is_hat=True, opcode="event_whenbackdropswitchesto")
120
+ EVENT_WHENGREATERTHAN = BlockShape(is_hat=True, opcode="event_whengreaterthan")
121
+ EVENT_WHENBROADCASTRECEIVED = BlockShape(is_hat=True, opcode="event_whenbroadcastreceived")
122
+ EVENT_BROADCAST = BlockShape(is_stack=True, opcode="event_broadcast")
123
+ EVENT_BROADCASTANDWAIT = BlockShape(is_stack=True, opcode="event_broadcastandwait")
124
+ EVENT_WHENTOUCHINGOBJECT = BlockShape(is_hat=True, opcode="event_whentouchingobject")
125
+ EVENT_BROADCAST_MENU = BlockShape(is_reporter=True, is_menu=True, opcode="event_broadcast_menu")
126
+ EVENT_TOUCHINGOBJECTMENU = BlockShape(is_reporter=True, is_menu=True, opcode="event_touchingobjectmenu")
127
+
128
+ CONTROL_WAIT = BlockShape(is_stack=True, opcode="control_wait")
129
+ CONTROL_FOREVER = BlockShape(is_c_mouth=True, is_stack=True, is_cap=True, opcode="control_forever")
130
+ CONTROL_IF = BlockShape(is_c_mouth=True, is_stack=True, opcode="control_if")
131
+ CONTROL_IF_ELSE = BlockShape(is_c_mouth=True, is_stack=True, opcode="control_if_else")
132
+ CONTROL_WAIT_UNTIL = BlockShape(is_stack=True, opcode="control_wait_until")
133
+ CONTROL_REPEAT_UNTIL = BlockShape(is_c_mouth=True, is_stack=True, opcode="control_repeat_until")
134
+ CONTROL_STOP = BlockShape(is_stack=True, is_cap=MUTATION_DEPENDENT, opcode="control_stop")
135
+ CONTROL_START_AS_CLONE = BlockShape(is_hat=True, opcode="control_start_as_clone")
136
+ CONTROL_CREATE_CLONE_OF = BlockShape(is_stack=True, opcode="control_create_clone_of")
137
+ CONTROL_DELETE_THIS_CLONE = BlockShape(is_stack=True, is_cap=True, opcode="control_delete_this_clone")
138
+ CONTROL_FOR_EACH = BlockShape(is_c_mouth=True, is_stack=True, opcode="control_for_each")
139
+ CONTROL_WHILE = BlockShape(is_c_mouth=True, is_stack=True, opcode="control_while")
140
+ CONTROL_GET_COUNTER = BlockShape(is_reporter=True, opcode="control_get_counter")
141
+ CONTROL_INCR_COUNTER = BlockShape(is_stack=True, opcode="control_incr_counter")
142
+ CONTROL_CLEAR_COUNTER = BlockShape(is_stack=True, opcode="control_clear_counter")
143
+ CONTROL_ALL_AT_ONCE = BlockShape(is_c_mouth=True, is_stack=True, opcode="control_all_at_once")
144
+ CONTROL_CREATE_CLONE_OF_MENU = BlockShape(is_reporter=True, is_menu=True, opcode="control_create_clone_of_menu")
145
+
146
+ SENSING_TOUCHINGOBJECT = BlockShape(is_reporter=True, is_boolean=True, opcode="sensing_touchingobject")
147
+ SENSING_TOUCHINGCOLOR = BlockShape(is_reporter=True, is_boolean=True, opcode="sensing_touchingcolor")
148
+ SENSING_COLORISTOUCHINGCOLOR = BlockShape(is_reporter=True, is_boolean=True, opcode="sensing_coloristouchingcolor")
149
+ SENSING_DISTANCETO = BlockShape(is_reporter=True, opcode="sensing_distanceto")
150
+ SENSING_ASKANDWAIT = BlockShape(is_stack=True, opcode="sensing_askandwait")
151
+ SENSING_ANSWER = BlockShape(is_reporter=True, opcode="sensing_answer")
152
+ SENSING_KEYPRESSED = BlockShape(is_reporter=True, is_boolean=True, opcode="sensing_keypressed")
153
+ SENSING_MOUSEDOWN = BlockShape(is_reporter=True, is_boolean=True, opcode="sensing_mousedown")
154
+ SENSING_MOUSEX = BlockShape(is_reporter=True, opcode="sensing_mousex")
155
+ SENSING_MOUSEY = BlockShape(is_reporter=True, opcode="sensing_mousey")
156
+ SENSING_SETDRAGMODE = BlockShape(is_stack=True, opcode="sensing_setdragmode")
157
+ SENSING_LOUDNESS = BlockShape(is_reporter=True, opcode="sensing_loudness")
158
+ SENSING_TIMER = BlockShape(is_reporter=True, opcode="sensing_timer")
159
+ SENSING_RESETTIMER = BlockShape(is_stack=True, opcode="sensing_resettimer")
160
+ SENSING_OF = BlockShape(is_reporter=True, opcode="sensing_of")
161
+ SENSING_CURRENT = BlockShape(is_reporter=True, opcode="sensing_current")
162
+ SENSING_DAYSSINCE2000 = BlockShape(is_reporter=True, opcode="sensing_dayssince2000")
163
+ SENSING_USERNAME = BlockShape(is_reporter=True, opcode="sensing_username")
164
+ SENSING_LOUD = BlockShape(is_reporter=True, is_boolean=True, opcode="sensing_loud")
165
+ SENSING_USERID = BlockShape(is_reporter=True, opcode="sensing_userid")
166
+ SENSING_TOUCHINGOBJECTMENU = BlockShape(is_reporter=True, is_menu=True, opcode="sensing_touchingobjectmenu")
167
+ SENSING_DISTANCETOMENU = BlockShape(is_reporter=True, is_menu=True, opcode="sensing_distancetomenu")
168
+ SENSING_KEYOPTIONS = BlockShape(is_reporter=True, is_menu=True, opcode="sensing_keyoptions")
169
+ SENSING_OF_OBJECT_MENU = BlockShape(is_reporter=True, is_menu=True, opcode="sensing_of_object_menu")
170
+
171
+ OPERATOR_ADD = BlockShape(is_reporter=True, opcode="operator_add")
172
+ OPERATOR_SUBTRACT = BlockShape(is_reporter=True, opcode="operator_subtract")
173
+ OPERATOR_MULTIPLY = BlockShape(is_reporter=True, opcode="operator_multiply")
174
+ OPERATOR_DIVIDE = BlockShape(is_reporter=True, opcode="operator_divide")
175
+ OPERATOR_RANDOM = BlockShape(is_reporter=True, opcode="operator_random")
176
+ OPERATOR_GT = BlockShape(is_reporter=True, is_boolean=True, opcode="operator_gt")
177
+ OPERATOR_LT = BlockShape(is_reporter=True, is_boolean=True, opcode="operator_lt")
178
+ OPERATOR_EQUALS = BlockShape(is_reporter=True, is_boolean=True, opcode="operator_equals")
179
+ OPERATOR_AND = BlockShape(is_reporter=True, is_boolean=True, opcode="operator_and")
180
+ OPERATOR_OR = BlockShape(is_reporter=True, is_boolean=True, opcode="operator_or")
181
+ OPERATOR_NOT = BlockShape(is_reporter=True, is_boolean=True, opcode="operator_not")
182
+ OPERATOR_JOIN = BlockShape(is_reporter=True, opcode="operator_join")
183
+ OPERATOR_LETTER_OF = BlockShape(is_reporter=True, opcode="operator_letter_of")
184
+ OPERATOR_LENGTH = BlockShape(is_reporter=True, opcode="operator_length")
185
+ OPERATOR_CONTAINS = BlockShape(is_reporter=True, is_boolean=True, opcode="operator_contains")
186
+ OPERATOR_MOD = BlockShape(is_reporter=True, opcode="operator_mod")
187
+ OPERATOR_ROUND = BlockShape(is_reporter=True, opcode="operator_round")
188
+ OPERATOR_MATHOP = BlockShape(is_reporter=True, opcode="operator_mathop")
189
+
190
+ DATA_VARIABLE = BlockShape(is_reporter=True, opcode="data_variable")
191
+ DATA_SETVARIABLETO = BlockShape(is_stack=True, opcode="data_setvariableto")
192
+ DATA_CHANGEVARIABLEBY = BlockShape(is_stack=True, opcode="data_changevariableby")
193
+ DATA_SHOWVARIABLE = BlockShape(is_stack=True, opcode="data_showvariable")
194
+ DATA_HIDEVARIABLE = BlockShape(is_stack=True, opcode="data_hidevariable")
195
+ DATA_LISTCONTENTS = BlockShape(is_reporter=True, opcode="data_listcontents")
196
+ DATA_ADDTOLIST = BlockShape(is_stack=True, opcode="data_addtolist")
197
+ DATA_DELETEOFLIST = BlockShape(is_stack=True, opcode="data_deleteoflist")
198
+ DATA_DELETEALLOFLIST = BlockShape(is_stack=True, opcode="data_deletealloflist")
199
+ DATA_INSERTATLIST = BlockShape(is_stack=True, opcode="data_insertatlist")
200
+ DATA_REPLACEITEMOFLIST = BlockShape(is_stack=True, opcode="data_replaceitemoflist")
201
+ DATA_ITEMOFLIST = BlockShape(is_reporter=True, is_boolean=True, opcode="data_itemoflist")
202
+ DATA_ITEMNUMOFLIST = BlockShape(is_reporter=True, opcode="data_itemnumoflist")
203
+ DATA_LENGTHOFLIST = BlockShape(is_reporter=True, opcode="data_lengthoflist")
204
+ DATA_LISTCONTAINSITEM = BlockShape(is_reporter=True, is_boolean=True, opcode="data_listcontainsitem")
205
+ DATA_SHOWLIST = BlockShape(is_stack=True, opcode="data_showlist")
206
+ DATA_HIDELIST = BlockShape(is_stack=True, opcode="data_hidelist")
207
+ DATA_LISTINDEXALL = BlockShape(is_reporter=True, is_menu=True, opcode="data_listindexall")
208
+ DATA_LISTINDEXRANDOM = BlockShape(is_reporter=True, is_menu=True, opcode="data_listindexrandom")
209
+
210
+ PROCEDURES_DEFINITION = BlockShape(is_hat=True, opcode="procedures_definition")
211
+ PROCEDURES_CALL = BlockShape(is_stack=True, opcode="procedures_call")
212
+ PROCEDURES_DECLARATION = BlockShape(is_stack=True, opcode="procedures_declaration")
213
+ PROCEDURES_PROTOTYPE = BlockShape(is_stack=True, opcode="procedures_prototype")
214
+
215
+ ARGUMENT_REPORTER_STRING_NUMBER = BlockShape(is_reporter=True, opcode="argument_reporter_string_number")
216
+ ARGUMENT_REPORTER_BOOLEAN = BlockShape(is_reporter=True, is_boolean=True, opcode="argument_reporter_boolean")
217
+ ARGUMENT_EDITOR_REPORTER = BlockShape(is_reporter=True, is_boolean=True, opcode="argument_editor_reporter")
218
+ ARGUMENT_EDITOR_STRING_NUMBER = BlockShape(is_reporter=True, opcode="argument_editor_string_number")
219
+
220
+ MUSIC_PLAYDRUMFORBEATS = BlockShape(is_stack=True, opcode="music_playDrumForBeats")
221
+ MUSIC_RESTFORBEATS = BlockShape(is_stack=True, opcode="music_restForBeats")
222
+ MUSIC_PLAYNOTEFORBEATS = BlockShape(is_stack=True, opcode="music_playNoteForBeats")
223
+ MUSIC_SETINSTRUMENT = BlockShape(is_stack=True, opcode="music_setInstrument")
224
+ MUSIC_SETTEMPO = BlockShape(is_stack=True, opcode="music_setTempo")
225
+ MUSIC_CHANGETEMPO = BlockShape(is_stack=True, opcode="music_changeTempo")
226
+ MUSIC_GETTEMPO = BlockShape(is_reporter=True, opcode="music_getTempo")
227
+ MUSIC_MIDIPLAYDRUMFORBEATS = BlockShape(is_stack=True, opcode="music_midiPlayDrumForBeats")
228
+ MUSIC_MIDISETINSTRUMENT = BlockShape(is_stack=True, opcode="music_midiSetInstrument")
229
+ MUSIC_MENU_DRUM = BlockShape(is_reporter=True, is_menu=True, opcode="music_menu_DRUM")
230
+ MUSIC_MENU_INSTRUMENT = BlockShape(is_reporter=True, is_menu=True, opcode="music_menu_INSTRUMENT")
231
+
232
+ PEN_CLEAR = BlockShape(is_stack=True, opcode="pen_clear")
233
+ PEN_STAMP = BlockShape(is_stack=True, opcode="pen_stamp")
234
+ PEN_PENDOWN = BlockShape(is_stack=True, opcode="pen_penDown")
235
+ PEN_PENUP = BlockShape(is_stack=True, opcode="pen_penUp")
236
+ PEN_SETPENCOLORTOCOLOR = BlockShape(is_stack=True, opcode="pen_setPenColorToColor")
237
+ PEN_CHANGEPENCOLORPARAMBY = BlockShape(is_stack=True, opcode="pen_changePenColorParamBy")
238
+ PEN_SETPENCOLORPARAMTO = BlockShape(is_stack=True, opcode="pen_setPenColorParamTo")
239
+ PEN_CHANGEPENSIZEBY = BlockShape(is_stack=True, opcode="pen_changePenSizeBy")
240
+ PEN_SETPENSIZETO = BlockShape(is_stack=True, opcode="pen_setPenSizeTo")
241
+ PEN_SETPENHUETONUMBER = BlockShape(is_stack=True, opcode="pen_setPenHueToNumber")
242
+ PEN_CHANGEPENHUEBY = BlockShape(is_stack=True, opcode="pen_changePenHueBy")
243
+ PEN_SETPENSHADETONUMBER = BlockShape(is_stack=True, opcode="pen_setPenShadeToNumber")
244
+ PEN_CHANGEPENSHADEBY = BlockShape(is_stack=True, opcode="pen_changePenShadeBy")
245
+ PEN_MENU_COLORPARAM = BlockShape(is_reporter=True, is_menu=True, opcode="pen_menu_colorParam")
246
+
247
+ VIDEOSENSING_WHENMOTIONGREATERTHAN = BlockShape(is_hat=True, opcode="videoSensing_whenMotionGreaterThan")
248
+ VIDEOSENSING_VIDEOON = BlockShape(is_reporter=True, opcode="videoSensing_videoOn")
249
+ VIDEOSENSING_VIDEOTOGGLE = BlockShape(is_stack=True, opcode="videoSensing_videoToggle")
250
+ VIDEOSENSING_SETVIDEOTRANSPARENCY = BlockShape(is_stack=True, opcode="videoSensing_setVideoTransparency")
251
+ VIDEOSENSING_MENU_ATTRIBUTE = BlockShape(is_reporter=True, is_menu=True, opcode="videoSensing_menu_ATTRIBUTE")
252
+ VIDEOSENSING_MENU_SUBJECT = BlockShape(is_reporter=True, is_menu=True, opcode="videoSensing_menu_SUBJECT")
253
+ VIDEOSENSING_MENU_VIDEO_STATE = BlockShape(is_reporter=True, is_menu=True, opcode="videoSensing_menu_VIDEO_STATE")
254
+
255
+ TEXT2SPEECH_SPEAKANDWAIT = BlockShape(is_stack=True, opcode="text2speech_speakAndWait")
256
+ TEXT2SPEECH_SETVOICE = BlockShape(is_stack=True, opcode="text2speech_setVoice")
257
+ TEXT2SPEECH_SETLANGUAGE = BlockShape(is_stack=True, opcode="text2speech_setLanguage")
258
+ TEXT2SPEECH_MENU_VOICES = BlockShape(is_reporter=True, is_menu=True, opcode="text2speech_menu_voices")
259
+ TEXT2SPEECH_MENU_LANGUAGES = BlockShape(is_reporter=True, is_menu=True, opcode="text2speech_menu_languages")
260
+ TRANSLATE_GETTRANSLATE = BlockShape(is_reporter=True, opcode="translate_getTranslate")
261
+ TRANSLATE_GETVIEWERLANGUAGE = BlockShape(is_reporter=True, opcode="translate_getViewerLanguage")
262
+ TRANSLATE_MENU_LANGUAGES = BlockShape(is_reporter=True, is_menu=True, opcode="translate_menu_languages")
263
+
264
+ MAKEYMAKEY_WHENMAKEYKEYPRESSED = BlockShape(is_hat=True, opcode="makeymakey_whenMakeyKeyPressed")
265
+ MAKEYMAKEY_WHENCODEPRESSED = BlockShape(is_hat=True, opcode="makeymakey_whenCodePressed")
266
+ MAKEYMAKEY_MENU_KEY = BlockShape(is_reporter=True, is_menu=True, opcode="makeymakey_menu_KEY")
267
+ MAKEYMAKEY_MENU_SEQUENCE = BlockShape(is_reporter=True, is_menu=True, opcode="makeymakey_menu_SEQUENCE")
268
+
269
+ MICROBIT_WHENBUTTONPRESSED = BlockShape(opcode="microbit_whenButtonPressed") # todo: finish this
270
+ MICROBIT_ISBUTTONPRESSED = BlockShape(opcode="microbit_isButtonPressed")
271
+ MICROBIT_WHENGESTURE = BlockShape(opcode="microbit_whenGesture")
272
+ MICROBIT_DISPLAYSYMBOL = BlockShape(opcode="microbit_displaySymbol")
273
+ MICROBIT_DISPLAYTEXT = BlockShape(opcode="microbit_displayText")
274
+ MICROBIT_DISPLAYCLEAR = BlockShape(opcode="microbit_displayClear")
275
+ MICROBIT_WHENTILTED = BlockShape(opcode="microbit_whenTilted")
276
+ MICROBIT_ISTILTED = BlockShape(opcode="microbit_isTilted")
277
+ MICROBIT_GETTILTANGLE = BlockShape(opcode="microbit_getTiltAngle")
278
+ MICROBIT_WHENPINCONNECTED = BlockShape(opcode="microbit_whenPinConnected")
279
+ MICROBIT_MENU_BUTTONS = BlockShape(opcode="microbit_menu_buttons")
280
+ MICROBIT_MENU_GESTURES = BlockShape(opcode="microbit_menu_gestures")
281
+ MICROBIT_MENU_TILTDIRECTIONANY = BlockShape(opcode="microbit_menu_tiltDirectionAny")
282
+ MICROBIT_MENU_TILTDIRECTION = BlockShape(opcode="microbit_menu_tiltDirection")
283
+ MICROBIT_MENU_TOUCHPINS = BlockShape(opcode="microbit_menu_touchPins")
284
+ MICROBIT_MENU_PINSTATE = BlockShape(opcode="microbit_menu_pinState")
285
+
286
+ EV3_MOTORTURNCLOCKWISE = BlockShape(opcode="ev3_motorTurnClockwise")
287
+ EV3_MOTORTURNCOUNTERCLOCKWISE = BlockShape(opcode="ev3_motorTurnCounterClockwise")
288
+ EV3_MOTORSETPOWER = BlockShape(opcode="ev3_motorSetPower")
289
+ EV3_GETMOTORPOSITION = BlockShape(opcode="ev3_getMotorPosition")
290
+ EV3_WHENBUTTONPRESSED = BlockShape(opcode="ev3_whenButtonPressed")
291
+ EV3_WHENDISTANCELESSTHAN = BlockShape(opcode="ev3_whenDistanceLessThan")
292
+ EV3_WHENBRIGHTNESSLESSTHAN = BlockShape(opcode="ev3_whenBrightnessLessThan")
293
+ EV3_BUTTONPRESSED = BlockShape(opcode="ev3_buttonPressed")
294
+ EV3_GETDISTANCE = BlockShape(opcode="ev3_getDistance")
295
+ EV3_GETBRIGHTNESS = BlockShape(opcode="ev3_getBrightness")
296
+ EV3_BEEP = BlockShape(opcode="ev3_beep")
297
+ EV3_MENU_MOTORPORTS = BlockShape(opcode="ev3_menu_motorPorts")
298
+ EV3_MENU_SENSORPORTS = BlockShape(opcode="ev3_menu_sensorPorts")
299
+
300
+ BOOST_MOTORONFOR = BlockShape(opcode="boost_motorOnFor")
301
+ BOOST_MOTORONFORROTATION = BlockShape(opcode="boost_motorOnForRotation")
302
+ BOOST_MOTORON = BlockShape(opcode="boost_motorOn")
303
+ BOOST_MOTOROFF = BlockShape(opcode="boost_motorOff")
304
+ BOOST_SETMOTORPOWER = BlockShape(opcode="boost_setMotorPower")
305
+ BOOST_SETMOTORDIRECTION = BlockShape(opcode="boost_setMotorDirection")
306
+ BOOST_GETMOTORPOSITION = BlockShape(opcode="boost_getMotorPosition")
307
+ BOOST_WHENCOLOR = BlockShape(opcode="boost_whenColor")
308
+ BOOST_SEEINGCOLOR = BlockShape(opcode="boost_seeingColor")
309
+ BOOST_WHENTILTED = BlockShape(opcode="boost_whenTilted")
310
+ BOOST_GETTILTANGLE = BlockShape(opcode="boost_getTiltAngle")
311
+ BOOST_SETLIGHTHUE = BlockShape(opcode="boost_setLightHue")
312
+ BOOST_MENU_MOTOR_ID = BlockShape(opcode="boost_menu_MOTOR_ID")
313
+ BOOST_MENU_MOTOR_DIRECTION = BlockShape(opcode="boost_menu_MOTOR_DIRECTION")
314
+ BOOST_MENU_MOTOR_REPORTER_ID = BlockShape(opcode="boost_menu_MOTOR_REPORTER_ID")
315
+ BOOST_MENU_COLOR = BlockShape(opcode="boost_menu_COLOR")
316
+ BOOST_MENU_TILT_DIRECTION_ANY = BlockShape(opcode="boost_menu_TILT_DIRECTION_ANY")
317
+ BOOST_MENU_TILT_DIRECTION = BlockShape(opcode="boost_menu_TILT_DIRECTION")
318
+
319
+ WEDO2_MOTORONFOR = BlockShape(opcode="wedo2_motorOnFor")
320
+ WEDO2_MOTORON = BlockShape(opcode="wedo2_motorOn")
321
+ WEDO2_MOTOROFF = BlockShape(opcode="wedo2_motorOff")
322
+ WEDO2_STARTMOTORPOWER = BlockShape(opcode="wedo2_startMotorPower")
323
+ WEDO2_SETMOTORDIRECTION = BlockShape(opcode="wedo2_setMotorDirection")
324
+ WEDO2_SETLIGHTHUE = BlockShape(opcode="wedo2_setLightHue")
325
+ WEDO2_WHENDISTANCE = BlockShape(opcode="wedo2_whenDistance")
326
+ WEDO2_WHENTILTED = BlockShape(opcode="wedo2_whenTilted")
327
+ WEDO2_GETDISTANCE = BlockShape(opcode="wedo2_getDistance")
328
+ WEDO2_ISTILTED = BlockShape(opcode="wedo2_isTilted")
329
+ WEDO2_GETTILTANGLE = BlockShape(opcode="wedo2_getTiltAngle")
330
+ WEDO2_PLAYNOTEFOR = BlockShape(opcode="wedo2_playNoteFor")
331
+ WEDO2_MENU_MOTOR_ID = BlockShape(opcode="wedo2_menu_MOTOR_ID")
332
+ WEDO2_MENU_MOTOR_DIRECTION = BlockShape(opcode="wedo2_menu_MOTOR_DIRECTION")
333
+ WEDO2_MENU_OP = BlockShape(opcode="wedo2_menu_OP")
334
+ WEDO2_MENU_TILT_DIRECTION_ANY = BlockShape(opcode="wedo2_menu_TILT_DIRECTION_ANY")
335
+ WEDO2_MENU_TILT_DIRECTION = BlockShape(opcode="wedo2_menu_TILT_DIRECTION")
336
+
337
+ GDXFOR_WHENGESTURE = BlockShape(opcode="gdxfor_whenGesture")
338
+ GDXFOR_WHENFORCEPUSHEDORPULLED = BlockShape(opcode="gdxfor_whenForcePushedOrPulled")
339
+ GDXFOR_GETFORCE = BlockShape(opcode="gdxfor_getForce")
340
+ GDXFOR_WHENTILTED = BlockShape(opcode="gdxfor_whenTilted")
341
+ GDXFOR_ISTILTED = BlockShape(opcode="gdxfor_isTilted")
342
+ GDXFOR_GETTILT = BlockShape(opcode="gdxfor_getTilt")
343
+ GDXFOR_ISFREEFALLING = BlockShape(opcode="gdxfor_isFreeFalling")
344
+ GDXFOR_GETSPINSPEED = BlockShape(opcode="gdxfor_getSpinSpeed")
345
+ GDXFOR_GETACCELERATION = BlockShape(opcode="gdxfor_getAcceleration")
346
+ GDXFOR_MENU_GESTUREOPTIONS = BlockShape(opcode="gdxfor_menu_gestureOptions")
347
+ GDXFOR_MENU_PUSHPULLOPTIONS = BlockShape(opcode="gdxfor_menu_pushPullOptions")
348
+ GDXFOR_MENU_TILTANYOPTIONS = BlockShape(opcode="gdxfor_menu_tiltAnyOptions")
349
+ GDXFOR_MENU_TILTOPTIONS = BlockShape(opcode="gdxfor_menu_tiltOptions")
350
+ GDXFOR_MENU_AXISOPTIONS = BlockShape(opcode="gdxfor_menu_axisOptions")
351
+
352
+ COREEXAMPLE_EXAMPLEOPCODE = BlockShape(is_reporter=True, opcode="coreExample_exampleOpcode")
353
+ COREEXAMPLE_EXAMPLEWITHINLINEIMAGE = BlockShape(is_stack=True, opcode="coreExample_exampleWithInlineImage")
354
+
355
+ NOTE = BlockShape(is_reporter=True, is_menu=True, opcode="note")
356
+ MATRIX = BlockShape(is_reporter=True, is_menu=True, opcode="matrix")
357
+ UNDEFINED = BlockShape(is_hat=True, is_cap=True, opcode="red_hat_block")
@@ -0,0 +1,51 @@
1
+ """
2
+ Module which stores the 'default' or 'current' selected Sprite/project (stored as a stack) which makes it easier to write scratch code directly in Python
3
+ """
4
+ from __future__ import annotations
5
+
6
+ from typing import Iterable, TYPE_CHECKING, Final, Literal
7
+
8
+ if TYPE_CHECKING:
9
+ from . import sprite, block, prim, comment
10
+ from . import commons
11
+
12
+ # TODO: should deque be used here?
13
+ class _SetSprite(commons.Singleton):
14
+ INSTANCE = 0
15
+ def __repr__(self):
16
+ return f'<Reminder to default your sprite to {current_sprite()}>'
17
+
18
+
19
+ SPRITE_DEFAULT: Final[Literal[_SetSprite.INSTANCE]] = _SetSprite.INSTANCE
20
+
21
+ _sprite_stack: list[sprite.Sprite] = []
22
+
23
+
24
+ def stack_add_sprite(_sprite: sprite.Sprite):
25
+ _sprite_stack.append(_sprite)
26
+
27
+
28
+ def current_sprite() -> sprite.Sprite | None:
29
+ """
30
+ Retrieve the default sprite from the top of the sprite stack
31
+ """
32
+ if len(_sprite_stack) == 0:
33
+ return None
34
+ return _sprite_stack[-1]
35
+
36
+
37
+ def pop_sprite(_sprite: sprite.Sprite) -> sprite.Sprite | None:
38
+ assert _sprite_stack.pop() == _sprite
39
+ return _sprite
40
+
41
+
42
+ def add_block(_block: block.Block | prim.Prim) -> block.Block | prim.Prim:
43
+ return current_sprite().add_block(_block)
44
+
45
+
46
+ def add_chain(*chain: Iterable[block.Block | prim.Prim]) -> block.Block | prim.Prim:
47
+ return current_sprite().add_chain(*chain)
48
+
49
+
50
+ def add_comment(_comment: comment.Comment):
51
+ return current_sprite().add_comment(_comment)
File without changes
@@ -0,0 +1,177 @@
1
+ from __future__ import annotations
2
+ from pathlib import Path
3
+ from typing import Union, Generic, TypeVar
4
+ from abc import ABC, abstractmethod
5
+ from collections.abc import Sequence
6
+
7
+ from lark import Lark, Transformer, Tree, Token, v_args
8
+ from lark.reconstruct import Reconstructor
9
+
10
+ R = TypeVar("R")
11
+ class SupportsRead(ABC, Generic[R]):
12
+ @abstractmethod
13
+ def read(self, size: int | None = -1) -> R:
14
+ pass
15
+
16
+ LANG_PATH = Path(__file__).parent / "language.lark"
17
+
18
+ lang = Lark(LANG_PATH.read_text(), maybe_placeholders=False)
19
+ reconstructor = Reconstructor(lang)
20
+
21
+ def parse(script: Union[str, bytes, SupportsRead[str], Path]) -> Tree:
22
+ if isinstance(script, Path):
23
+ script = script.read_text()
24
+ if isinstance(script, SupportsRead):
25
+ read_data = script.read()
26
+ assert isinstance(read_data, str)
27
+ script = read_data
28
+ if isinstance(script, bytes):
29
+ script = script.decode("utf-8")
30
+ return lang.parse(script)
31
+
32
+ def unparse(tree: Tree) -> str:
33
+ return reconstructor.reconstruct(tree)
34
+
35
+ class PrettyUnparser(Transformer):
36
+ INDENT_STRING = " "
37
+
38
+ @classmethod
39
+ def _indent(cls, text):
40
+ if not text:
41
+ return ""
42
+ return "\n".join(cls.INDENT_STRING + line for line in text.splitlines())
43
+
44
+ def PARAM_NAME(self, token):
45
+ return token.value
46
+
47
+ def BLOCK_NAME(self, token):
48
+ return token.value
49
+
50
+ def EVENT(self, token):
51
+ return token.value
52
+
53
+ def CONTROL_BLOCK_NAME(self, token):
54
+ return token.value
55
+
56
+ def _PREPROC_INSTR_CONTENT(self, token):
57
+ return token.value
58
+
59
+ def _COMMMENT_CONTENT(self, token):
60
+ return token.value
61
+
62
+ @v_args(inline=True)
63
+ def hat(self, child):
64
+ return child
65
+
66
+ @v_args(inline=True)
67
+ def param(self, child):
68
+ return child
69
+
70
+ @v_args(inline=True)
71
+ def value_param(self, name):
72
+ return name
73
+
74
+ @v_args(inline=True)
75
+ def bool_param(self, name):
76
+ return f"<{name}>"
77
+
78
+ @v_args(inline=True)
79
+ def event_hat(self, event_name):
80
+ return f"when ({event_name})"
81
+
82
+ def block_hat(self, items):
83
+ name, *params = items
84
+ params_str = ", ".join(params)
85
+ return f"custom_block {name} ({params_str})"
86
+
87
+ @v_args(inline=True)
88
+ def PREPROC_INSTR(self, content):
89
+ return f"{content}"
90
+
91
+ @v_args(inline=True)
92
+ def COMMMENT(self, content):
93
+ return f"{content}"
94
+
95
+ def block(self, items):
96
+ params = []
97
+ inner_blocks = []
98
+ comments = []
99
+ for i in items[1:]:
100
+ if not isinstance(i, Tree):
101
+ continue
102
+ if str(i.data) == "block_content":
103
+ inner_blocks.extend(i.children)
104
+ if str(i.data) == "block_params":
105
+ params.extend(i.children)
106
+ if str(i.data) == "comments":
107
+ comments.extend(i.children)
108
+ block_name = items[0]
109
+ block_text = f"{block_name}({', '.join(params)})" if params or not inner_blocks else f"{block_name}"
110
+ if inner_blocks:
111
+ blocks_content = "\n".join(inner_blocks)
112
+ indented_content = self._indent(blocks_content)
113
+ block_text += f" {{\n{indented_content}\n}}"
114
+ if comments:
115
+ block_text += f" {' '.join(comments)}"
116
+ return block_text
117
+
118
+ def LITERAL_NUMBER(self, number: str):
119
+ return number
120
+
121
+ def expr(self, items):
122
+ text = items[0]
123
+ if len(items) > 1:
124
+ text += f" {' '.join(items[1].children)}"
125
+ return text
126
+
127
+ def low_expr1(self, items):
128
+ text = f"({items[0]})" if " " in items[0] else items[0]
129
+ if len(items) > 1:
130
+ text += f" {' '.join(items[1].children)}"
131
+ return text
132
+
133
+ @v_args(inline=True)
134
+ def low_expr2(self, item):
135
+ return item
136
+
137
+ def addition(self, items):
138
+ return items[0] + " + " + items[1]
139
+
140
+ def subtraction(self, items):
141
+ return items[0] + " - " + items[1]
142
+
143
+ def multiplication(self, items):
144
+ return items[0] + " * " + items[1]
145
+
146
+ def division(self, items):
147
+ return items[0] + " / " + items[1]
148
+
149
+ def top_level_block(self, items):
150
+ first_item = items[0]
151
+ if first_item.startswith("%%") or first_item.startswith("##"):
152
+ return first_item
153
+
154
+ hat, *blocks = items
155
+ blocks_content = "\n".join(blocks)
156
+ indented_content = self._indent(blocks_content)
157
+ return f"{hat} {{\n{indented_content}\n}}"
158
+
159
+ def start(self, items):
160
+ return "\n\n".join(items)
161
+
162
+ def pretty_unparse(tree: Tree):
163
+ return PrettyUnparser().transform(tree)
164
+
165
+ if __name__ == "__main__":
166
+ EXAMPLE_FILE = Path(__file__).parent / "example.txt"
167
+ tree = parse(EXAMPLE_FILE)
168
+ print(tree.pretty())
169
+ print()
170
+ print()
171
+ print(tree)
172
+ print()
173
+ print()
174
+ print(unparse(tree))
175
+ print()
176
+ print()
177
+ print(pretty_unparse(tree))
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from . import base, block, sprite, build_defaulting
4
+ from typing import Optional
5
+
6
+
7
+ class Comment(base.IDComponent):
8
+ """
9
+ Represents a comment in the scratch editor.
10
+ """
11
+ def __init__(self, _id: Optional[str] = None, _block: Optional[block.Block] = None, x: int = 0, y: int = 0, width: int = 200,
12
+ height: int = 200, minimized: bool = False, text: str = '', *, _block_id: Optional[str] = None,
13
+ _sprite: sprite.Sprite = build_defaulting.SPRITE_DEFAULT, pos: Optional[tuple[int, int]] = None):
14
+ self.block = _block
15
+ self._block_id = _block_id
16
+ """
17
+ ID of connected block. Will be set to None upon sprite initialization when the block attribute is updated to the relevant Block.
18
+ """
19
+ if pos is not None:
20
+ x, y = pos
21
+
22
+ self.x = x
23
+ self.y = y
24
+
25
+ self.width = width
26
+ self.height = height
27
+
28
+ self.minimized = minimized
29
+ self.text = text
30
+
31
+ super().__init__(_id, _sprite)
32
+
33
+ def __repr__(self):
34
+ return f"Comment<{self.text[:10]!r}...>"
35
+
36
+ @property
37
+ def block_id(self):
38
+ """
39
+ Retrieve the id of the associateed block (if applicable)
40
+ """
41
+ if self.block is not None:
42
+ return self.block.id
43
+ elif self._block_id is not None:
44
+ return self._block_id
45
+ else:
46
+ return None
47
+
48
+ @staticmethod
49
+ def from_json(data: tuple[str, dict]):
50
+ assert len(data) == 2
51
+ _id, data = data
52
+
53
+ _block_id = data.get("blockId")
54
+
55
+ x = data.get("x", 0)
56
+ y = data.get("y", 0)
57
+
58
+ width = data.get("width", 100)
59
+ height = data.get("height", 100)
60
+
61
+ minimized = data.get("minimized", False)
62
+ text = data.get("text")
63
+
64
+ ret = Comment(_id, None, x, y, width, height, minimized, text, _block_id=_block_id)
65
+ return ret
66
+
67
+ def to_json(self) -> dict:
68
+ return {
69
+ "blockId": self.block_id,
70
+ "x": self.x, "y": self.y,
71
+ "width": self.width, "height": self.height,
72
+ "minimized": self.minimized,
73
+ "text": self.text,
74
+ }
75
+
76
+ def link_using_sprite(self):
77
+ if self._block_id is not None:
78
+ self.block = self.sprite.find_block(self._block_id, "id")
79
+ if self.block is not None:
80
+ self._block_id = None