scratchattach 2.1.13__py3-none-any.whl → 2.1.15b0__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 (55) hide show
  1. scratchattach/cloud/_base.py +12 -8
  2. scratchattach/cloud/cloud.py +19 -7
  3. scratchattach/editor/asset.py +59 -5
  4. scratchattach/editor/base.py +82 -31
  5. scratchattach/editor/block.py +86 -15
  6. scratchattach/editor/blockshape.py +10 -6
  7. scratchattach/editor/build_defaulting.py +6 -2
  8. scratchattach/editor/code_translation/__init__.py +0 -0
  9. scratchattach/editor/code_translation/parse.py +177 -0
  10. scratchattach/editor/comment.py +6 -0
  11. scratchattach/editor/commons.py +49 -19
  12. scratchattach/editor/extension.py +10 -3
  13. scratchattach/editor/field.py +9 -0
  14. scratchattach/editor/inputs.py +4 -1
  15. scratchattach/editor/meta.py +11 -3
  16. scratchattach/editor/monitor.py +46 -38
  17. scratchattach/editor/mutation.py +11 -4
  18. scratchattach/editor/pallete.py +24 -25
  19. scratchattach/editor/prim.py +2 -2
  20. scratchattach/editor/project.py +9 -3
  21. scratchattach/editor/sprite.py +19 -6
  22. scratchattach/editor/twconfig.py +2 -1
  23. scratchattach/editor/vlb.py +1 -1
  24. scratchattach/eventhandlers/_base.py +2 -2
  25. scratchattach/eventhandlers/cloud_events.py +2 -2
  26. scratchattach/eventhandlers/cloud_requests.py +3 -3
  27. scratchattach/eventhandlers/cloud_server.py +3 -3
  28. scratchattach/eventhandlers/message_events.py +1 -1
  29. scratchattach/other/other_apis.py +4 -4
  30. scratchattach/other/project_json_capabilities.py +3 -3
  31. scratchattach/site/_base.py +13 -12
  32. scratchattach/site/activity.py +11 -43
  33. scratchattach/site/alert.py +227 -0
  34. scratchattach/site/backpack_asset.py +2 -2
  35. scratchattach/site/browser_cookie3_stub.py +17 -0
  36. scratchattach/site/browser_cookies.py +27 -21
  37. scratchattach/site/classroom.py +51 -34
  38. scratchattach/site/cloud_activity.py +4 -4
  39. scratchattach/site/comment.py +30 -8
  40. scratchattach/site/forum.py +101 -69
  41. scratchattach/site/project.py +42 -21
  42. scratchattach/site/session.py +170 -80
  43. scratchattach/site/studio.py +4 -4
  44. scratchattach/site/user.py +179 -64
  45. scratchattach/utils/commons.py +35 -23
  46. scratchattach/utils/enums.py +44 -5
  47. scratchattach/utils/exceptions.py +10 -0
  48. scratchattach/utils/requests.py +57 -31
  49. {scratchattach-2.1.13.dist-info → scratchattach-2.1.15b0.dist-info}/METADATA +8 -3
  50. scratchattach-2.1.15b0.dist-info/RECORD +66 -0
  51. {scratchattach-2.1.13.dist-info → scratchattach-2.1.15b0.dist-info}/WHEEL +1 -1
  52. scratchattach/editor/sbuild.py +0 -2837
  53. scratchattach-2.1.13.dist-info/RECORD +0 -63
  54. {scratchattach-2.1.13.dist-info → scratchattach-2.1.15b0.dist-info}/licenses/LICENSE +0 -0
  55. {scratchattach-2.1.13.dist-info → scratchattach-2.1.15b0.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,21 @@
1
+ """
2
+ Enum & dataclass representing extension categories
3
+ """
4
+
1
5
  from __future__ import annotations
2
6
 
3
7
 
4
8
  from dataclasses import dataclass
5
9
 
6
10
  from . import base
7
- from ..utils import enums
11
+ from scratchattach.utils import enums
8
12
 
9
13
 
10
- @dataclass(init=True, repr=True)
14
+ @dataclass
11
15
  class Extension(base.JSONSerializable):
16
+ """
17
+ Represents an extension in the Scratch block pallete - e.g. video sensing
18
+ """
12
19
  code: str
13
20
  name: str = None
14
21
 
@@ -40,4 +47,4 @@ class Extensions(enums._EnumWrapper):
40
47
  TRANSLATE = Extension("translate", "Translate Extension")
41
48
  VIDEOSENSING = Extension("videoSensing", "Video Sensing Extension")
42
49
  WEDO2 = Extension("wedo2", "LEGO Education WeDo 2.0 Extension")
43
- COREEXAMPLE = Extension("coreExample", "CoreEx Extension")
50
+ COREEXAMPLE = Extension("coreExample", "CoreEx Extension") # hidden extension!
@@ -38,6 +38,9 @@ class Field(base.BlockSubComponent):
38
38
 
39
39
  @property
40
40
  def value_id(self):
41
+ """
42
+ Get the id of the value associated with this field (if applicable) - when value is var/list/broadcast
43
+ """
41
44
  if self.id is not None:
42
45
  return self.id
43
46
  else:
@@ -48,6 +51,9 @@ class Field(base.BlockSubComponent):
48
51
 
49
52
  @property
50
53
  def value_str(self):
54
+ """
55
+ Convert the associated value to a string - if this is a VLB, return the VLB name
56
+ """
51
57
  if not isinstance(self.value, base.NamedIDComponent):
52
58
  return self.value
53
59
  else:
@@ -55,6 +61,9 @@ class Field(base.BlockSubComponent):
55
61
 
56
62
  @property
57
63
  def name(self) -> str:
64
+ """
65
+ Fetch the name of this field using the associated block
66
+ """
58
67
  for _name, _field in self.block.fields.items():
59
68
  if _field is self:
60
69
  return _name
@@ -8,8 +8,11 @@ from . import base, commons, prim
8
8
  from dataclasses import dataclass
9
9
 
10
10
 
11
- @dataclass(init=True)
11
+ @dataclass
12
12
  class ShadowStatus:
13
+ """
14
+ Dataclass representing a possible shadow value and giving it a name
15
+ """
13
16
  idx: int
14
17
  name: str
15
18
 
@@ -7,7 +7,7 @@ from . import base, commons
7
7
  from typing import Optional
8
8
 
9
9
 
10
- @dataclass(init=True, repr=True)
10
+ @dataclass
11
11
  class PlatformMeta(base.JSONSerializable):
12
12
  name: str = None
13
13
  url: str = field(repr=True, default=None)
@@ -36,8 +36,13 @@ EDIT_META = True
36
36
  META_SET_PLATFORM = False
37
37
 
38
38
 
39
- def set_meta_platform(true_false: bool = False):
39
+ def set_meta_platform(true_false: bool = None):
40
+ """
41
+ toggle whether to set the meta platform by default (or specify a value)
42
+ """
40
43
  global META_SET_PLATFORM
44
+ if true_false is None:
45
+ true_false = bool(1 - true_false)
41
46
  META_SET_PLATFORM = true_false
42
47
 
43
48
 
@@ -69,7 +74,10 @@ class Meta(base.JSONSerializable):
69
74
 
70
75
  @property
71
76
  def vm_is_valid(self):
72
- # Thanks to TurboWarp for this pattern ↓↓↓↓, I just copied it
77
+ """
78
+ Check whether the vm value is valid using a regex
79
+ Thanks to TurboWarp for this pattern ↓↓↓↓, I just copied it
80
+ """
73
81
  return re.match("^([0-9]+\\.[0-9]+\\.[0-9]+)($|-)", self.vm) is not None
74
82
 
75
83
  def to_json(self):
@@ -1,8 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import warnings
3
4
  from typing import Optional, TYPE_CHECKING
4
5
 
6
+ from typing_extensions import deprecated
7
+
5
8
  if TYPE_CHECKING:
9
+ from .block import Block
6
10
  from . import project
7
11
 
8
12
  from . import base
@@ -26,6 +30,8 @@ class Monitor(base.ProjectSubcomponent):
26
30
  """
27
31
  Represents a variable/list monitor
28
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!
29
35
  """
30
36
  assert isinstance(reporter, base.SpriteSubComponent) or reporter is None
31
37
 
@@ -135,41 +141,43 @@ class Monitor(base.ProjectSubcomponent):
135
141
  self.reporter = new_vlb
136
142
  self.reporter_id = None
137
143
 
138
- # @staticmethod
139
- # def from_reporter(reporter: Block, _id: str = None, mode: str = "default",
140
- # opcode: str = None, sprite_name: str = None, value=0, width: int | float = 0,
141
- # height: int | float = 0,
142
- # x: int | float = 5, y: int | float = 5, visible: bool = False, slider_min: int | float = 0,
143
- # slider_max: int | float = 100, is_discrete: bool = True, params: dict = None):
144
- # if "reporter" not in reporter.stack_type:
145
- # warnings.warn(f"{reporter} is not a reporter block; the monitor will return '0'")
146
- # elif "(menu)" in reporter.stack_type:
147
- # warnings.warn(f"{reporter} is a menu block; the monitor will return '0'")
148
- # # Maybe add note that length of list doesn't work fsr?? idk
149
- # if _id is None:
150
- # _id = reporter.opcode
151
- # if opcode is None:
152
- # opcode = reporter.opcode # .replace('_', ' ')
153
-
154
- # if params is None:
155
- # params = {}
156
- # for field in reporter.fields:
157
- # if field.value_id is None:
158
- # params[field.id] = field.value
159
- # else:
160
- # params[field.id] = field.value, field.value_id
161
-
162
- # return Monitor(
163
- # _id,
164
- # mode,
165
- # opcode,
166
-
167
- # params,
168
- # sprite_name,
169
- # value,
170
-
171
- # width, height,
172
- # x, y,
173
- # visible,
174
- # slider_min, slider_max, is_discrete
175
- # )
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
+ )
@@ -6,13 +6,13 @@ from dataclasses import dataclass
6
6
  from typing import Optional, TYPE_CHECKING, Iterable, Any
7
7
 
8
8
  from . import base, commons
9
- from ..utils import enums
9
+ from scratchattach.utils import enums
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from . import block
13
13
 
14
14
 
15
- @dataclass(init=True)
15
+ @dataclass
16
16
  class ArgumentType(base.Base):
17
17
  type: str
18
18
  proc_str: str
@@ -38,7 +38,7 @@ class ArgumentType(base.Base):
38
38
  return None
39
39
 
40
40
 
41
- @dataclass(init=True, repr=True)
41
+ @dataclass
42
42
  class ArgSettings(base.Base):
43
43
  ids: bool
44
44
  names: bool
@@ -61,7 +61,7 @@ class ArgSettings(base.Base):
61
61
  return int(self) > int(other)
62
62
 
63
63
 
64
- @dataclass(init=True, repr=True)
64
+ @dataclass
65
65
  class Argument(base.MutationSubComponent):
66
66
  name: str
67
67
  default: str = ''
@@ -103,6 +103,10 @@ class ArgTypes(enums._EnumWrapper):
103
103
 
104
104
 
105
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
+
106
110
  if _proc_code is None:
107
111
  return None
108
112
  token = ''
@@ -209,6 +213,9 @@ class Mutation(base.BlockSubComponent):
209
213
 
210
214
  @property
211
215
  def parsed_proc_code(self) -> list[str, ArgumentType] | None:
216
+ """
217
+ Parse the proc code into arguments & strings
218
+ """
212
219
  return parse_proc_code(self.proc_code)
213
220
 
214
221
  @staticmethod
@@ -6,43 +6,42 @@ May want to completely change this later
6
6
  """
7
7
  from __future__ import annotations
8
8
 
9
- from dataclasses import dataclass
9
+ from dataclasses import dataclass, field
10
+ from typing import Optional
10
11
 
11
12
  from . import prim
12
- from ..utils.enums import _EnumWrapper
13
+ from scratchattach.utils.enums import _EnumWrapper
13
14
 
14
15
 
15
- @dataclass(init=True, repr=True)
16
+ @dataclass
16
17
  class FieldUsage:
17
18
  name: str
18
- value_type: prim.PrimTypes = None
19
+ value_type: Optional[prim.PrimTypes] = None
19
20
 
20
21
 
21
- @dataclass(init=True, repr=True)
22
+ @dataclass
22
23
  class SpecialFieldUsage(FieldUsage):
23
24
  name: str
24
- attrs: list[str] = None
25
- if attrs is None:
26
- attrs = []
25
+ value_type: None = None # Order cannot be changed
26
+ attrs: list[str] = field(default_factory=list)
27
27
 
28
- value_type: None = None
29
28
 
30
29
 
31
- @dataclass(init=True, repr=True)
30
+ @dataclass
32
31
  class InputUsage:
33
32
  name: str
34
- value_type: prim.PrimTypes = None
35
- default_obscurer: BlockUsage = None
33
+ value_type: Optional[prim.PrimTypes] = None
34
+ default_obscurer: Optional[BlockUsage] = None
36
35
 
37
36
 
38
- @dataclass(init=True, repr=True)
37
+ @dataclass
39
38
  class BlockUsage:
40
39
  opcode: str
41
- fields: list[FieldUsage] = None
40
+ fields: Optional[list[FieldUsage]] = None
42
41
  if fields is None:
43
42
  fields = []
44
43
 
45
- inputs: list[InputUsage] = None
44
+ inputs: Optional[list[InputUsage]] = None
46
45
  if inputs is None:
47
46
  inputs = []
48
47
 
@@ -51,41 +50,41 @@ class BlockUsages(_EnumWrapper):
51
50
  # Special Enum blocks
52
51
  MATH_NUMBER = BlockUsage(
53
52
  "math_number",
54
- [SpecialFieldUsage("NUM", ["name", "value"])]
53
+ [SpecialFieldUsage("NUM", attrs=["name", "value"])]
55
54
  )
56
55
  MATH_POSITIVE_NUMBER = BlockUsage(
57
56
  "math_positive_number",
58
- [SpecialFieldUsage("NUM", ["name", "value"])]
57
+ [SpecialFieldUsage("NUM", attrs=["name", "value"])]
59
58
  )
60
59
  MATH_WHOLE_NUMBER = BlockUsage(
61
60
  "math_whole_number",
62
- [SpecialFieldUsage("NUM", ["name", "value"])]
61
+ [SpecialFieldUsage("NUM", attrs=["name", "value"])]
63
62
  )
64
63
  MATH_INTEGER = BlockUsage(
65
64
  "math_integer",
66
- [SpecialFieldUsage("NUM", ["name", "value"])]
65
+ [SpecialFieldUsage("NUM", attrs=["name", "value"])]
67
66
  )
68
67
  MATH_ANGLE = BlockUsage(
69
68
  "math_angle",
70
- [SpecialFieldUsage("NUM", ["name", "value"])]
69
+ [SpecialFieldUsage("NUM", attrs=["name", "value"])]
71
70
  )
72
71
  COLOUR_PICKER = BlockUsage(
73
72
  "colour_picker",
74
- [SpecialFieldUsage("COLOUR", ["name", "value"])]
73
+ [SpecialFieldUsage("COLOUR", attrs=["name", "value"])]
75
74
  )
76
75
  TEXT = BlockUsage(
77
76
  "text",
78
- [SpecialFieldUsage("TEXT", ["name", "value"])]
77
+ [SpecialFieldUsage("TEXT", attrs=["name", "value"])]
79
78
  )
80
79
  EVENT_BROADCAST_MENU = BlockUsage(
81
80
  "event_broadcast_menu",
82
- [SpecialFieldUsage("BROADCAST_OPTION", ["name", "id", "value", "variableType"])]
81
+ [SpecialFieldUsage("BROADCAST_OPTION", attrs=["name", "id", "value", "variableType"])]
83
82
  )
84
83
  DATA_VARIABLE = BlockUsage(
85
84
  "data_variable",
86
- [SpecialFieldUsage("VARIABLE", ["name", "id", "value", "variableType"])]
85
+ [SpecialFieldUsage("VARIABLE", attrs=["name", "id", "value", "variableType"])]
87
86
  )
88
87
  DATA_LISTCONTENTS = BlockUsage(
89
88
  "data_listcontents",
90
- [SpecialFieldUsage("LIST", ["name", "id", "value", "variableType"])]
89
+ [SpecialFieldUsage("LIST", attrs=["name", "id", "value", "variableType"])]
91
90
  )
@@ -5,10 +5,10 @@ from dataclasses import dataclass
5
5
  from typing import Optional, Callable, Final
6
6
 
7
7
  from . import base, sprite, vlb, commons, build_defaulting
8
- from ..utils import enums, exceptions
8
+ from scratchattach.utils import enums, exceptions
9
9
 
10
10
 
11
- @dataclass(init=True, repr=True)
11
+ @dataclass
12
12
  class PrimType(base.JSONSerializable):
13
13
  code: int
14
14
  name: str
@@ -8,12 +8,15 @@ from typing import Optional, Iterable, Generator, BinaryIO
8
8
  from zipfile import ZipFile
9
9
 
10
10
  from . import base, meta, extension, monitor, sprite, asset, vlb, twconfig, comment, commons
11
- from ..site import session
12
- from ..site.project import get_project
13
- from ..utils import exceptions
11
+ from scratchattach.site import session
12
+ from scratchattach.site.project import get_project
13
+ from scratchattach.utils import exceptions
14
14
 
15
15
 
16
16
  class Project(base.JSONExtractable):
17
+ """
18
+ sa.editor's equivalent of the ProjectBody. Represents the editor contents of a scratch project
19
+ """
17
20
  def __init__(self, _name: Optional[str] = None, _meta: Optional[meta.Meta] = None, _extensions: Iterable[extension.Extension] = (),
18
21
  _monitors: Iterable[monitor.Monitor] = (), _sprites: Iterable[sprite.Sprite] = (), *,
19
22
  _asset_data: Optional[list[asset.AssetFile]] = None, _session: Optional[session.Session] = None):
@@ -268,6 +271,9 @@ class Project(base.JSONExtractable):
268
271
  os.system(f"explorer.exe \"{fp}\"")
269
272
 
270
273
  def add_monitor(self, _monitor: monitor.Monitor) -> monitor.Monitor:
274
+ """
275
+ Bind a monitor to this project. Doing these manually can lead to interesting results.
276
+ """
271
277
  _monitor.project = self
272
278
  _monitor.reporter_id = self.new_id
273
279
  self.monitors.append(_monitor)
@@ -11,6 +11,8 @@ if TYPE_CHECKING:
11
11
  from . import asset
12
12
 
13
13
  class Sprite(base.ProjectSubcomponent, base.JSONExtractable):
14
+ _local_globals: list[base.NamedIDComponent]
15
+ asset_data: list[asset.AssetFile]
14
16
  def __init__(self, is_stage: bool = False, name: str = '', _current_costume: int = 1, _layer_order: Optional[int] = None,
15
17
  _volume: int = 100,
16
18
  _broadcasts: Optional[list[vlb.Broadcast]] = None,
@@ -120,6 +122,9 @@ class Sprite(base.ProjectSubcomponent, base.JSONExtractable):
120
122
  _comment.link_using_sprite()
121
123
 
122
124
  def add_local_global(self, _vlb: base.NamedIDComponent):
125
+ """
126
+ Add a global variable/list to this sprite (for when an overarching project/stage is not available)
127
+ """
123
128
  self._local_globals.append(_vlb)
124
129
  _vlb.sprite = self
125
130
 
@@ -128,11 +133,11 @@ class Sprite(base.ProjectSubcomponent, base.JSONExtractable):
128
133
  _variable.sprite = self
129
134
 
130
135
  def add_list(self, _list: vlb.List):
131
- self.variables.append(_list)
136
+ self.lists.append(_list)
132
137
  _list.sprite = self
133
138
 
134
139
  def add_broadcast(self, _broadcast: vlb.Broadcast):
135
- self.variables.append(_broadcast)
140
+ self.broadcasts.append(_broadcast)
136
141
  _broadcast.sprite = self
137
142
 
138
143
  def add_vlb(self, _vlb: base.NamedIDComponent):
@@ -151,18 +156,20 @@ class Sprite(base.ProjectSubcomponent, base.JSONExtractable):
151
156
  return _block
152
157
 
153
158
  _block.sprite = self
159
+ new_id = self.new_id
154
160
 
155
161
  if isinstance(_block, block.Block):
156
- self.blocks[self.new_id] = _block
162
+ self.blocks[new_id] = _block
163
+ _block.id = new_id
157
164
  _block.link_using_sprite()
158
165
 
159
166
  elif isinstance(_block, prim.Prim):
160
- self.prims[self.new_id] = _block
167
+ self.prims[new_id] = _block
161
168
  _block.link_using_sprite()
162
169
 
163
170
  return _block
164
171
 
165
- def add_chain(self, *chain: Iterable[block.Block | prim.Prim]) -> block.Block | prim.Prim:
172
+ def add_chain(self, *chain: block.Block | prim.Prim) -> block.Block | prim.Prim:
166
173
  """
167
174
  Adds a list of blocks to the sprite **AND RETURNS THE FIRST BLOCK**
168
175
  :param chain:
@@ -173,6 +180,8 @@ class Sprite(base.ProjectSubcomponent, base.JSONExtractable):
173
180
  _prev = self.add_block(chain[0])
174
181
 
175
182
  for _block in chain[1:]:
183
+ if not isinstance(_prev, block.Block) or not isinstance(_block, block.Block):
184
+ continue
176
185
  _prev = _prev.attach_block(_block)
177
186
 
178
187
  return chain[0]
@@ -206,7 +215,11 @@ class Sprite(base.ProjectSubcomponent, base.JSONExtractable):
206
215
  """
207
216
  :return: All vlbs associated with the sprite. No local globals are added
208
217
  """
209
- return self.variables + self.lists + self.broadcasts
218
+ vlbs: list[base.NamedIDComponent] = []
219
+ vlbs.extend(self.variables)
220
+ vlbs.extend(self.lists)
221
+ vlbs.extend(self.broadcasts)
222
+ return vlbs
210
223
 
211
224
  @property
212
225
  def assets(self) -> list[asset.Costume | asset.Sound]:
@@ -17,7 +17,7 @@ You can move, resize, and minimize this comment, but don't edit it by hand. This
17
17
  _END = " // _twconfig_"
18
18
 
19
19
 
20
- @dataclass(init=True, repr=True)
20
+ @dataclass
21
21
  class TWConfig(base.JSONSerializable):
22
22
  framerate: int = None,
23
23
  interpolation: bool = False,
@@ -100,6 +100,7 @@ def get_twconfig_data(string: str) -> dict | None:
100
100
  return None
101
101
 
102
102
 
103
+ # todo: move this to commons.py?
103
104
  def none_if_eq(data, compare) -> Any | None:
104
105
  """
105
106
  Returns None if data and compare are the same
@@ -9,7 +9,7 @@ from __future__ import annotations
9
9
  from typing import Optional, Literal
10
10
 
11
11
  from . import base, sprite, build_defaulting
12
- from ..utils import exceptions
12
+ from scratchattach.utils import exceptions
13
13
 
14
14
 
15
15
  class Variable(base.NamedIDComponent):
@@ -5,8 +5,8 @@ from collections import defaultdict
5
5
  from threading import Thread
6
6
  from collections.abc import Callable
7
7
  import traceback
8
- from ..utils.requests import Requests as requests
9
- from ..utils import exceptions
8
+ from scratchattach.utils.requests import requests
9
+ from scratchattach.utils import exceptions
10
10
 
11
11
  class BaseEventHandler(ABC):
12
12
  _events: defaultdict[str, list[Callable]]
@@ -1,9 +1,9 @@
1
1
  """CloudEvents class"""
2
2
  from __future__ import annotations
3
3
 
4
- from ..cloud import _base
4
+ from scratchattach.cloud import _base
5
5
  from ._base import BaseEventHandler
6
- from ..site import cloud_activity
6
+ from scratchattach.site import cloud_activity
7
7
  import time
8
8
  import json
9
9
  from collections.abc import Iterator
@@ -2,13 +2,13 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  from .cloud_events import CloudEvents
5
- from ..site import project
5
+ from scratchattach.site import project
6
6
  from threading import Thread, Event, current_thread
7
7
  import time
8
8
  import random
9
9
  import traceback
10
- from ..utils.encoder import Encoding
11
- from ..utils import exceptions
10
+ from scratchattach.utils.encoder import Encoding
11
+ from scratchattach.utils import exceptions
12
12
 
13
13
  class Request:
14
14
 
@@ -2,11 +2,11 @@ from __future__ import annotations
2
2
 
3
3
  from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket
4
4
  from threading import Thread
5
- from ..utils import exceptions
5
+ from scratchattach.utils import exceptions
6
6
  import json
7
7
  import time
8
- from ..site import cloud_activity
9
- from ..site.user import User
8
+ from scratchattach.site import cloud_activity
9
+ from scratchattach.site.user import User
10
10
  from ._base import BaseEventHandler
11
11
 
12
12
  class TwCloudSocket(WebSocket):
@@ -1,7 +1,7 @@
1
1
  """MessageEvents class"""
2
2
  from __future__ import annotations
3
3
 
4
- from ..site import user
4
+ from scratchattach.site import user
5
5
  from ._base import BaseEventHandler
6
6
  import time
7
7
 
@@ -4,10 +4,10 @@ from __future__ import annotations
4
4
  import json
5
5
  from dataclasses import dataclass, field
6
6
 
7
- from ..utils import commons
8
- from ..utils.enums import Languages, Language, TTSVoices, TTSVoice
9
- from ..utils.exceptions import BadRequest, InvalidLanguage, InvalidTTSGender
10
- from ..utils.requests import Requests as requests
7
+ from scratchattach.utils import commons
8
+ from scratchattach.utils.enums import Languages, Language, TTSVoices, TTSVoice
9
+ from scratchattach.utils.exceptions import BadRequest, InvalidLanguage, InvalidTTSGender
10
+ from scratchattach.utils.requests import requests
11
11
  from typing import Optional
12
12
 
13
13
 
@@ -10,9 +10,9 @@ import random
10
10
  import string
11
11
  import zipfile
12
12
  from abc import ABC, abstractmethod
13
- from ..utils import exceptions
14
- from ..utils.commons import empty_project_json
15
- from ..utils.requests import Requests as requests
13
+ from scratchattach.utils import exceptions
14
+ from scratchattach.utils.commons import empty_project_json
15
+ from scratchattach.utils.requests import requests
16
16
  # noinspection PyPep8Naming
17
17
  def load_components(json_data: list, ComponentClass: type, target_list: list):
18
18
  for element in json_data: