diff --git a/scratchattach/editor/asset.py b/scratchattach/editor/asset.py index 0338692e..aba02062 100644 --- a/scratchattach/editor/asset.py +++ b/scratchattach/editor/asset.py @@ -11,7 +11,7 @@ @dataclass(init=True, repr=True) class AssetFile: """ - Represents the file information for an asset + Represents the file information for an asset (not the asset metdata) - stores the filename, data, and md5 hash """ filename: str @@ -19,7 +19,7 @@ class AssetFile: _md5: str = field(repr=False, default_factory=str) @property - def data(self): + def data(self) -> bytes: """ Return the contents of the asset file, as bytes """ @@ -35,9 +35,9 @@ def data(self): return self._data @property - def md5(self): + def md5(self) -> str: """ - Compute/retrieve the md5 hash value of the asset file data + Compute/retrieve the md5 hex-digest of the asset file data """ if self._md5 is None: self._md5 = md5(self.data).hexdigest() @@ -51,7 +51,7 @@ def __init__(self, file_name: str = "b7853f557e4426412e64bb3da6531a99.svg", _sprite: commons.SpriteInput = build_defaulting.SPRITE_DEFAULT): """ - Represents a generic asset. Can be a sound or an image. + Represents a generic asset, with metadata. Can be a sound or a costume. https://en.scratch-wiki.info/wiki/Scratch_File_Format#Assets """ try: @@ -72,14 +72,14 @@ def __repr__(self): @property def folder(self): """ - Get the folder name of this asset, based on the asset name. Uses the turbowarp syntax + Get the folder name of this asset, based on the asset name. Uses the TurboWarp syntax """ return commons.get_folder_name(self.name) @property def name_nfldr(self): """ - Get the asset name after removing the folder name + Get the asset name after removing the folder name. Uses the TurboWarp syntax """ return commons.get_name_nofldr(self.name) @@ -96,14 +96,16 @@ def md5ext(self): """ Get the exact file name, as it would be within an sb3 file equivalent to the md5ext value using in scratch project JSON + + (alias for file_name) """ return self.file_name @property def parent(self): """ - Return the project that this asset is attached to. If there is no attached project, - try returning the attached sprite + Return the project (body) that this asset is attached to. If there is no attached project, + try returning the attached sprite instead. """ if self.project is None: return self.sprite diff --git a/scratchattach/editor/backpack_json.py b/scratchattach/editor/backpack_json.py index 5e101ea6..1e3bb699 100644 --- a/scratchattach/editor/backpack_json.py +++ b/scratchattach/editor/backpack_json.py @@ -1,18 +1,16 @@ """ -Module to deal with the backpack's weird JSON format, by overriding with new load methods +Module to deal with the backpack's weird JSON format, by overriding editor classes with new load methods """ from __future__ import annotations from . import block, prim, field, inputs, mutation, sprite -def parse_prim_fields(_fields: dict[str]) -> tuple[str | None, str | None, str | None]: +def parse_prim_fields(_fields: dict[str, dict[str, str]]) -> tuple[str | None, str | None, str | None]: """ Function for reading the fields in a backpack **primitive** """ for key, value in _fields.items(): - key: str - value: dict[str, str] prim_value, prim_name, prim_id = (None,) * 3 if key == "NUM": prim_value = value.get("value") @@ -103,7 +101,7 @@ def load_script(_script_data: list[dict]) -> sprite.Sprite: """ Loads a script into a sprite from the backpack JSON format :param _script_data: Backpack script JSON data - :return: a blockchain object containing the script + :return: a Sprite object containing the script """ # Using a sprite since it simplifies things, e.g. local global loading _blockchain = sprite.Sprite() diff --git a/scratchattach/editor/base.py b/scratchattach/editor/base.py index f637bc30..b500a239 100644 --- a/scratchattach/editor/base.py +++ b/scratchattach/editor/base.py @@ -52,7 +52,7 @@ def to_json(self): def save_json(self, name: str = ''): """ - Save a json file + Save json to a file. Adds '.json' for you. """ data = self.to_json() with open(f"{self.__class__.__name__.lower()}{name}.json", "w") as f: diff --git a/scratchattach/editor/block.py b/scratchattach/editor/block.py index 2571c3bb..ed71deeb 100644 --- a/scratchattach/editor/block.py +++ b/scratchattach/editor/block.py @@ -68,8 +68,8 @@ def link_subcomponents(self): def add_input(self, name: str, _input: inputs.Input) -> Self: """ - Add an input to the block. - """ # not sure what else to say + Attach an input object to the block. + """ self.inputs[name] = _input for val in (_input.value, _input.obscurer): if isinstance(val, Block): @@ -78,15 +78,15 @@ def add_input(self, name: str, _input: inputs.Input) -> Self: def add_field(self, name: str, _field: field.Field) -> Self: """ - Add a field to the block. - """ # not sure what else to sa + Attach a field object to the block. + """ self.fields[name] = _field return self def set_mutation(self, _mutation: mutation.Mutation) -> Self: """ - Attach a mutation object and call mutation.link_arguments() - """ # this comment explains *what* this does, not *why* + Attach a mutation object and link it, also asking the mutation to link its own subcomponents. + """ self.mutation = _mutation _mutation.block = self _mutation.link_arguments() @@ -113,14 +113,15 @@ def check_toplevel(self): @property def target(self): """ - Alias for sprite - """ # remove this? + Alias for .sprite + """ + # should this be deprecated? return self.sprite @property def block_shape(self) -> blockshape.BlockShape: """ - Search for the blockshape stored in blockshape.py + Search for & return the associated blockshape stored in blockshape.py :return: The block's block shape (by opcode) """ _shape = blockshape.BlockShapes.find(self.opcode, "opcode") @@ -133,7 +134,7 @@ def block_shape(self) -> blockshape.BlockShape: @property def can_next(self): """ - :return: Whether the block *can* have a next block (basically checks if it's not a cap block, also considering the behaviour of control_stop) + :return: Whether the block *can* have a next block (checks if it's not a cap block, but also considering the special behaviour of control_stop) """ _shape = self.block_shape if _shape.is_cap is not blockshape.MUTATION_DEPENDENT: @@ -141,7 +142,8 @@ def can_next(self): else: if self.mutation is None: # If there's no mutation, let's just assume yes - warnings.warn(f"{self} has no mutation! Assuming we can add block ;-;") + # add filterwarnings? + warnings.warn(f"{self} has no mutation! Assuming we can add blocks!") return True return self.mutation.has_next @@ -150,6 +152,7 @@ def can_next(self): def id(self) -> str: """ Work out the id of this block by searching through the sprite dictionary + If one cannot be found, generate a new one and return that. """ if self._id: return self._id @@ -191,8 +194,9 @@ def next_id(self): @property def relatives(self) -> list[Block]: """ - :return: A list of blocks which are related to this block (e.g. parent, next, inputs) + :return: A list of blocks which are related to this block (i.e. parent & next) """ + # TODO: consider adding input blocks? _ret = [] def yield_block(_block: Block | None): @@ -209,6 +213,7 @@ def children(self) -> list[Block | prim.Prim]: """ :return: A list of blocks that are inside of this block, **NOT INCLUDING THE ATTACHED BLOCK** """ + # does this include procedure definitions' inner block? _children = [] for _input in self.inputs.values(): if isinstance(_input.value, Block) or isinstance(_input.value, prim.Prim): @@ -223,7 +228,8 @@ def previous_chain(self): """ Recursive getter method to get all previous blocks in the blockchain (until hitting a top-level block) """ - if self.parent is None: # todo: use is_top_level? + # TODO: check if this hits the recursion limit + if self.parent is None: # TODO: use is_top_level? return [self] return [self] + self.parent.previous_chain @@ -233,6 +239,7 @@ def attached_chain(self): """ Recursive getter method to get all next blocks in the blockchain (until hitting a bottom-levell block) """ + # TODO: check if this hits the recursion limit if self.next is None: return [self] @@ -248,8 +255,7 @@ def complete_chain(self): @property def top_level_block(self): """ - Get the first block in the block stack that this block is part of - same as the old stack_parent property from sbedtior v1 + Get the first (top level) block in the block stack that this block is part of """ return self.previous_chain[-1] @@ -266,7 +272,7 @@ def stack_tree(self): Useful for showing a block stack in the console, using pprint :return: A tree-like nested list structure representing the stack of blocks, including inputs, starting at this block """ - _tree = [self] + _tree: list[Block | prim.Prim | list[Block]] = [self] for child in self.children: if isinstance(child, prim.Prim): _tree.append(child) @@ -281,7 +287,7 @@ def stack_tree(self): @property def category(self): """ - Works out what category of block this is using the opcode. Does not perform validation + Works out what category of block this is as a string, using the opcode. Does not perform validation """ return self.opcode.split('_')[0] @@ -526,7 +532,7 @@ def attach_block(self, new: Block) -> Block: def duplicate_single_block(self) -> Block: return self.attach_block(self.dcopy()) - def attach_chain(self, *chain: Iterable[Block]) -> Block: + def attach_chain(self, *chain: Block) -> Block: attaching_block = self for _block in chain: attaching_block = attaching_block.attach_block(_block) @@ -576,4 +582,3 @@ def delete_chain(self): """ for _block in self.attached_chain: _block.delete_single_block() - diff --git a/scratchattach/editor/build_defaulting.py b/scratchattach/editor/build_defaulting.py index 99fb9867..60238210 100644 --- a/scratchattach/editor/build_defaulting.py +++ b/scratchattach/editor/build_defaulting.py @@ -9,7 +9,7 @@ from . import sprite, block, prim, comment from . import commons - +# TODO: should deque be used here? class _SetSprite(commons.Singleton): INSTANCE = 0 def __repr__(self): diff --git a/scratchattach/editor/commons.py b/scratchattach/editor/commons.py index 9962db8a..bd986e4a 100644 --- a/scratchattach/editor/commons.py +++ b/scratchattach/editor/commons.py @@ -6,7 +6,7 @@ import json import random import string -from typing_extensions import Optional, Final, Any, TYPE_CHECKING, Union, Self +from typing_extensions import Optional, Final, Any, TYPE_CHECKING, Union, Self, TypeVar from enum import EnumMeta, Enum if TYPE_CHECKING: @@ -16,130 +16,13 @@ else: SpriteInput = Any +T = TypeVar('T') from scratchattach.utils import exceptions DIGITS: Final[tuple[str, ...]] = tuple("0123456789") -ID_CHARS: Final[str] = string.ascii_letters + string.digits # + string.punctuation - - # Strangely enough, it seems like something in string.punctuation causes issues. Not sure why - - -def _read_json_number(_str: str) -> float | int: - ret = '' - - minus = _str[0] == '-' - if minus: - ret += '-' - _str = _str[1:] - - def read_fraction(sub: str): - sub_ret = '' - if sub[0] == '.': - sub_ret += '.' - sub = sub[1:] - while sub[0] in DIGITS: - sub_ret += sub[0] - sub = sub[1:] - - return sub_ret, sub - - def read_exponent(sub: str): - sub_ret = '' - if sub[0].lower() == 'e': - sub_ret += sub[0] - sub = sub[1:] - - if sub[0] in "-+": - sub_ret += sub[0] - sub = sub[1:] - - if sub[0] not in DIGITS: - raise exceptions.UnclosedJSONError(f"Invalid exponent {sub}") - - while sub[0] in DIGITS: - sub_ret += sub[0] - sub = sub[1:] - - return sub_ret - - if _str[0] == '0': - ret += '0' - _str = _str[1:] - - elif _str[0] in DIGITS[1:9]: - while _str[0] in DIGITS: - ret += _str[0] - _str = _str[1:] - - frac, _str = read_fraction(_str) - ret += frac - - ret += read_exponent(_str) - - return json.loads(ret) - -# todo: consider if this should be moved to util.commons instead of editor.commons -# note: this is currently unused code -def consume_json(_str: str, i: int = 0) -> str | float | int | dict | list | bool | None: - """ - *'gobble up some JSON until we hit something not quite so tasty'* - - Reads a JSON string and stops at the natural end (i.e. when brackets close, or when quotes end, etc.) - """ - # Named by ChatGPT - section = ''.join(_str[i:]) - if section.startswith("true"): - return True - elif section.startswith("false"): - return False - elif section.startswith("null"): - return None - elif section[0] in "0123456789.-": - return _read_json_number(section) - - depth = 0 - json_text = '' - out_string = True - - for char in section: - json_text += char - - if char == '"': - if len(json_text) > 1: - unescaped = json_text[-2] != '\\' - else: - unescaped = True - if unescaped: - out_string ^= True - if out_string: - depth -= 1 - else: - depth += 1 - - if out_string: - if char in "[{": - depth += 1 - elif char in "}]": - depth -= 1 - - if depth == 0 and json_text.strip(): - return json.loads(json_text.strip()) - - raise exceptions.UnclosedJSONError(f"Unclosed JSON string, read {json_text}") - - -def is_partial_json(_str: str, i: int = 0) -> bool: - try: - consume_json(_str, i) - return True - - except exceptions.UnclosedJSONError: - return False - - except ValueError: - return False +ID_CHARS: Final[str] = string.ascii_letters + string.digits # + string.punctuation def is_valid_json(_str: Any) -> bool: @@ -185,7 +68,7 @@ def safe_get(lst: list | tuple, _i: int, default: Optional[Any] = None) -> Any: return lst[_i] -def trim_final_nones(lst: list) -> list: +def trim_final_nones(lst: list[T]) -> list[T]: """ Removes the last None values from a list until a non-None value is hit. :param lst: list which will **not** be modified. @@ -215,6 +98,7 @@ def gen_id() -> str: The old 'naïve' method but that chances of a repeat are so miniscule Have to check if whitespace chars break it May later add checking within sprites so that we don't need such long ids (we can save space this way) + If this is implemented, we would need to be careful when merging sprites/adding blocks etc """ return ''.join(random.choices(ID_CHARS, k=20)) @@ -257,22 +141,24 @@ def get_name_nofldr(name: str) -> str: else: return name[len(fldr) + 2:] + class SingletonMeta(EnumMeta): - + def __call__(self, value=0, *args, **kwds): if value != 0: raise ValueError("Value must be 0.") old_bases = self.__bases__ - self.__bases__ = old_bases + (Enum, ) + self.__bases__ = old_bases + (Enum,) result = super().__call__(value, *args, **kwds) self.__bases__ = old_bases return result + if TYPE_CHECKING: Singleton = Enum else: class Singleton(metaclass=SingletonMeta): - + def __new__(cls, val=None): if cls is Singleton: raise TypeError("Singleton cannot be created directly.") @@ -281,28 +167,27 @@ def __new__(cls, val=None): if val == 0: return super().__new__(cls) raise TypeError("Has no instance.") - + def __init__(self, *args, **kwds): pass - + def __repr__(self): return self.__class__.__name__ - + def __str__(self): return self.__class__.__name__ - + def __format__(self, format_spec): return str.__format__(str(self), format_spec) - + def __hash__(self): return hash(self.__class__) - + def __reduce_ex__(self, proto): return self.__class__, () - - def __deepcopy__(self,memo): + + def __deepcopy__(self, memo): return self - + def __copy__(self): return self - diff --git a/scratchattach/editor/field.py b/scratchattach/editor/field.py index b8e4a898..c71a42d0 100644 --- a/scratchattach/editor/field.py +++ b/scratchattach/editor/field.py @@ -93,7 +93,7 @@ def from_json(data: list[str, str | None]): _value, _id = data return Field(_value, _id) - def to_json(self) -> dict: + def to_json(self): return commons.trim_final_nones([ self.value_str, self.value_id ]) diff --git a/scratchattach/editor/inputs.py b/scratchattach/editor/inputs.py index 3a8dba8d..18218393 100644 --- a/scratchattach/editor/inputs.py +++ b/scratchattach/editor/inputs.py @@ -11,7 +11,7 @@ @dataclass class ShadowStatus: """ - Dataclass representing a possible shadow value and giving it a name + Dataclass representing a possible shadow value for a block and giving it a name """ idx: int name: str @@ -33,8 +33,7 @@ def find(cls, idx: int) -> ShadowStatus: if status.idx == idx: return status - if not 1 <= idx <= 3: - raise ValueError(f"Invalid ShadowStatus idx={idx}") + raise ValueError(f"Invalid ShadowStatus idx={idx}") class Input(base.BlockSubComponent): @@ -111,6 +110,10 @@ def add_pblock(pblock: prim.Prim | block.Block | None): return data def link_using_block(self): + """ + Link the Input object to any menu blocks, obscurer blocks, sprites, and links any of its subcomponents + """ + # Link to value if self._id is not None: new_value = self.sprite.find_block(self._id, "id") diff --git a/scratchattach/editor/meta.py b/scratchattach/editor/meta.py index 2cfc8061..886c482a 100644 --- a/scratchattach/editor/meta.py +++ b/scratchattach/editor/meta.py @@ -9,13 +9,16 @@ @dataclass class PlatformMeta(base.JSONSerializable): + """ + Represents a TurboWarp platform meta object + """ name: str = None url: str = field(repr=True, default=None) def __bool__(self): return self.name is not None or self.url is not None - def to_json(self) -> dict: + def to_json(self): _json = {"name": self.name, "url": self.url} commons.remove_nones(_json) return _json @@ -42,7 +45,7 @@ def set_meta_platform(true_false: bool = None): """ global META_SET_PLATFORM if true_false is None: - true_false = bool(1 - true_false) + true_false = bool(1 - META_SET_PLATFORM) META_SET_PLATFORM = true_false @@ -76,12 +79,12 @@ def __repr__(self): def vm_is_valid(self): """ Check whether the vm value is valid using a regex - Thanks to TurboWarp for this pattern ↓↓↓↓, I just copied it + regex pattern from TurboWarp ↓↓↓↓ """ return re.match("^([0-9]+\\.[0-9]+\\.[0-9]+)($|-)", self.vm) is not None def to_json(self): - _json = { + _json: dict[str, str | dict[str, str]] = { "semver": self.semver, "vm": self.vm, "agent": self.agent @@ -92,9 +95,9 @@ def to_json(self): return _json @staticmethod - def from_json(data): + def from_json(data: dict[str, str | dict[str, str]] | None): if data is None: - data = "" + data = {"semver": "3.0.0"} semver = data["semver"] vm = data.get("vm") diff --git a/scratchattach/editor/monitor.py b/scratchattach/editor/monitor.py index adc48ee5..c4840a8f 100644 --- a/scratchattach/editor/monitor.py +++ b/scratchattach/editor/monitor.py @@ -144,8 +144,8 @@ def link_using_project(self): self.reporter_id = None # todo: consider reimplementing this - @deprecated("This method does not work correctly (This may be fixed in the future)") @staticmethod + @deprecated("This method does not work correctly (This may be fixed in the future)") def from_reporter(reporter: block.Block, _id: str = None, mode: str = "default", opcode: str = None, sprite_name: str = None, value=0, width: int | float = 0, height: int | float = 0, diff --git a/scratchattach/editor/mutation.py b/scratchattach/editor/mutation.py index 7db99cb0..ffb64581 100644 --- a/scratchattach/editor/mutation.py +++ b/scratchattach/editor/mutation.py @@ -1,3 +1,7 @@ +""" +Contains the mutation class and handlers for Arguments/ArgumentTypes/ArgSettings, and utilities for handling proc codes +""" + from __future__ import annotations import json @@ -41,6 +45,9 @@ def default(self) -> str | None: @dataclass class ArgSettings(base.Base): + """ + Contains whether the ids, names, and defaults of arguments in a mutation are None or not - i.e. the configuration of the arguments + """ ids: bool names: bool defaults: bool diff --git a/scratchattach/editor/pallete.py b/scratchattach/editor/pallete.py index 4f157544..2bd65f2e 100644 --- a/scratchattach/editor/pallete.py +++ b/scratchattach/editor/pallete.py @@ -1,8 +1,6 @@ """ Collection of block information, stating input/field names and opcodes -New version of sbuild.py - -May want to completely change this later +Not ready for use """ from __future__ import annotations diff --git a/scratchattach/editor/prim.py b/scratchattach/editor/prim.py index 969b37da..2fc3e65c 100644 --- a/scratchattach/editor/prim.py +++ b/scratchattach/editor/prim.py @@ -1,3 +1,7 @@ +""" +The PrimType(s) and Prim classes +""" + from __future__ import annotations import warnings diff --git a/scratchattach/editor/project.py b/scratchattach/editor/project.py index ed8299b8..3ab2336e 100644 --- a/scratchattach/editor/project.py +++ b/scratchattach/editor/project.py @@ -16,7 +16,7 @@ class Project(base.JSONExtractable): """ - sa.editor's equivalent of the ProjectBody. Represents the editor contents of a scratch project + A Project (body). Represents the editor contents of a scratch project """ def __init__(self, _name: Optional[str] = None, _meta: Optional[meta.Meta] = None, _extensions: Iterable[extension.Extension] = (), _monitors: Iterable[monitor.Monitor] = (), _sprites: Iterable[sprite.Sprite] = (), *, @@ -332,6 +332,7 @@ def arg_get(name: str) -> str: if goto_origin: _block.x, _block.y = 0, 0 + # TODO: Add special handling for turbowarp debugger blocks if _block.opcode in ("procedures_call", "procedures_prototype", "procedures_definition"): if _block.mutation is None: continue diff --git a/scratchattach/editor/sprite.py b/scratchattach/editor/sprite.py index e00e8fae..06cda18a 100644 --- a/scratchattach/editor/sprite.py +++ b/scratchattach/editor/sprite.py @@ -345,7 +345,7 @@ def to_json(self) -> dict: return _json # Finding/getting from list/dict attributes - def find_asset(self, value: str, by: str = "name", multiple: bool = False, a_type: Optional[type]=None) -> asset.Asset | asset.Sound | asset.Costume | list[asset.Asset | asset.Sound | asset.Costume]: + def find_asset(self, value: str, by: str = "name", multiple: bool = False, a_type: Optional[type]=None) -> None | asset.Asset | asset.Sound | asset.Costume | list[asset.Asset | asset.Sound | asset.Costume]: if a_type is None: a_type = asset.Asset @@ -366,8 +366,9 @@ def find_asset(self, value: str, by: str = "name", multiple: bool = False, a_typ if multiple: return _ret + return None - def find_variable(self, value: str, by: str = "name", multiple: bool = False) -> vlb.Variable | list[vlb.Variable]: + def find_variable(self, value: str, by: str = "name", multiple: bool = False) -> None | vlb.Variable | list[vlb.Variable]: _ret = [] by = by.lower() for _variable in self.variables + self._local_globals: @@ -394,8 +395,9 @@ def find_variable(self, value: str, by: str = "name", multiple: bool = False) -> if multiple: return _ret + return None - def find_list(self, value: str, by: str = "name", multiple: bool = False) -> vlb.List | list[vlb.List]: + def find_list(self, value: str, by: str = "name", multiple: bool = False) -> None | vlb.List | list[vlb.List]: _ret = [] by = by.lower() for _list in self.lists + self._local_globals: @@ -421,8 +423,9 @@ def find_list(self, value: str, by: str = "name", multiple: bool = False) -> vlb if multiple: return _ret + return None - def find_broadcast(self, value: str, by: str = "name", multiple: bool = False) -> vlb.Broadcast | list[ + def find_broadcast(self, value: str, by: str = "name", multiple: bool = False) -> None | vlb.Broadcast | list[ vlb.Broadcast]: _ret = [] by = by.lower() @@ -449,6 +452,7 @@ def find_broadcast(self, value: str, by: str = "name", multiple: bool = False) - if multiple: return _ret + return None def find_vlb(self, value: str, by: str = "name", multiple: bool = False) -> vlb.Variable | vlb.List | vlb.Broadcast | list[ @@ -466,7 +470,7 @@ def find_vlb(self, value: str, by: str = "name", return _ret return self.find_broadcast(value, by) - def find_block(self, value: str | Any, by: str, multiple: bool = False) -> block.Block | prim.Prim | list[ + def find_block(self, value: str | Any, by: str, multiple: bool = False) -> None | block.Block | prim.Prim | list[ block.Block | prim.Prim]: _ret = [] by = by.lower() @@ -512,6 +516,7 @@ def find_block(self, value: str | Any, by: str, multiple: bool = False) -> block if multiple: return _ret + return None def export(self, fp: Optional[str] = None, *, export_as_zip: bool = True): if fp is None: diff --git a/scratchattach/editor/vlb.py b/scratchattach/editor/vlb.py index 6570f7f2..7fc5825a 100644 --- a/scratchattach/editor/vlb.py +++ b/scratchattach/editor/vlb.py @@ -73,7 +73,7 @@ def __init__(self, _id: str, _name: str, _value: Optional[list[str | int | float https://en.scratch-wiki.info/wiki/Scratch_File_Format#Targets:~:text=lists,as%20an%20array """ if _value is None: - _value = [] + _value: list[str | int | float] = [] self.value = _value super().__init__(_id, _name, _sprite) @@ -91,7 +91,7 @@ def from_json(data: tuple[str, tuple[str, str | int | float] | tuple[str, str | return List(_id, _name, _value) - def to_json(self) -> tuple[str, tuple[str, str | int | float, bool] | tuple[str, str | int | float]]: + def to_json(self) -> tuple[str, list[str | int | float]]: """ Returns List data as a tuple """ diff --git a/scratchattach/utils/enums.py b/scratchattach/utils/enums.py index f5dc27fb..f4704d63 100644 --- a/scratchattach/utils/enums.py +++ b/scratchattach/utils/enums.py @@ -18,6 +18,7 @@ class Language: single_gender: bool = None +# should this underscore be removed class _EnumWrapper(Enum): @classmethod def find(cls, value, by: str, apply_func: Optional[Callable] = None):