From e7842759dccd03ff9f4dd4fe8005bb27425efbfd Mon Sep 17 00:00:00 2001 From: "Robin.Schmidt" Date: Tue, 21 Jul 2026 16:36:43 +0200 Subject: [PATCH 1/7] Activated some `ruff` rules, mostly sorted/unused imports. --- construct_editor/core/commands.py | 6 +- construct_editor/core/construct_editor.py | 4 +- construct_editor/core/context_menu.py | 19 ++- construct_editor/core/entries.py | 130 +++++++++--------- construct_editor/core/model.py | 4 +- construct_editor/core/preprocessor.py | 2 +- construct_editor/gallery/__init__.py | 3 +- construct_editor/gallery/example_cmd_resp.py | 13 +- construct_editor/gallery/example_ipstack.py | 3 +- construct_editor/gallery/example_pe32coff.py | 1 + construct_editor/gallery/test_aligned.py | 2 +- construct_editor/gallery/test_array.py | 6 +- .../gallery/test_bits_swapped_bitwise.py | 2 +- construct_editor/gallery/test_bitwise.py | 2 +- .../gallery/test_bytes_greedybytes.py | 2 +- construct_editor/gallery/test_checksum.py | 3 +- construct_editor/gallery/test_compressed.py | 2 +- construct_editor/gallery/test_computed.py | 4 +- construct_editor/gallery/test_const.py | 4 +- .../gallery/test_dataclass_bit_struct.py | 4 +- .../gallery/test_dataclass_struct.py | 6 +- construct_editor/gallery/test_default.py | 4 +- construct_editor/gallery/test_enum.py | 2 +- construct_editor/gallery/test_fixedsized.py | 2 +- construct_editor/gallery/test_flag.py | 2 +- construct_editor/gallery/test_flagsenum.py | 2 +- construct_editor/gallery/test_greedyrange.py | 4 +- construct_editor/gallery/test_ifthenelse.py | 7 +- .../gallery/test_ifthenelse_nested_switch.py | 7 +- construct_editor/gallery/test_nullstripped.py | 2 +- .../gallery/test_nullterminated.py | 2 +- construct_editor/gallery/test_padded.py | 2 +- .../gallery/test_padded_string.py | 4 +- construct_editor/gallery/test_pass.py | 2 +- .../gallery/test_pointer_peek_seek_tell.py | 2 +- construct_editor/gallery/test_renamed.py | 4 +- .../gallery/test_select_complex.py | 3 +- .../gallery/test_stringencodded.py | 4 +- construct_editor/gallery/test_switch.py | 2 +- .../gallery/test_switch_dataclass.py | 4 +- construct_editor/gallery/test_tenum.py | 4 +- construct_editor/gallery/test_tflagsenum.py | 4 +- construct_editor/gallery/test_timestamp.py | 6 +- construct_editor/main.py | 2 +- .../wx_widgets/wx_construct_editor.py | 24 ++-- .../wx_widgets/wx_construct_hex_editor.py | 4 +- .../wx_widgets/wx_exception_dialog.py | 4 +- construct_editor/wx_widgets/wx_hex_editor.py | 14 +- construct_editor/wx_widgets/wx_obj_view.py | 27 ++-- .../wx_widgets/wx_python_code_editor.py | 2 +- doc/screenshot_scripts/bitwise.py | 1 - pyproject.toml | 8 +- 52 files changed, 204 insertions(+), 179 deletions(-) diff --git a/construct_editor/core/commands.py b/construct_editor/core/commands.py index 17ae3b1..421f751 100644 --- a/construct_editor/core/commands.py +++ b/construct_editor/core/commands.py @@ -22,7 +22,7 @@ def __init__(self, max_commands: int) -> None: self._max_commands = max_commands self._history: t.List[Command] = [] - self._current_command_idx: t.Optional[int] = None + self._current_command_idx: int | None = None def can_undo(self) -> bool: """ @@ -131,7 +131,7 @@ def clear_commands(self): self._history.clear() self._current_command_idx = None - def get_current_command(self) -> t.Optional[Command]: + def get_current_command(self) -> Command | None: """ Returns the current command. """ @@ -140,7 +140,7 @@ def get_current_command(self) -> t.Optional[Command]: return self._history[self._current_command_idx] - def get_next_command(self) -> t.Optional[Command]: + def get_next_command(self) -> Command | None: """ Returns the next command. """ diff --git a/construct_editor/core/construct_editor.py b/construct_editor/core/construct_editor.py index 3427d00..9c2ac32 100644 --- a/construct_editor/core/construct_editor.py +++ b/construct_editor/core/construct_editor.py @@ -30,7 +30,7 @@ def reload(self): """ @abc.abstractmethod - def show_parse_error_message(self, msg: t.Optional[str], ex: t.Optional[Exception]): + def show_parse_error_message(self, msg: str | None, ex: Exception | None): """ Show an parse error message to the user. @@ -38,7 +38,7 @@ def show_parse_error_message(self, msg: t.Optional[str], ex: t.Optional[Exceptio """ @abc.abstractmethod - def show_build_error_message(self, msg: t.Optional[str], ex: t.Optional[Exception]): + def show_build_error_message(self, msg: str | None, ex: Exception | None): """ Show an build error message to the user. diff --git a/construct_editor/core/context_menu.py b/construct_editor/core/context_menu.py index 98635a9..cea410d 100644 --- a/construct_editor/core/context_menu.py +++ b/construct_editor/core/context_menu.py @@ -5,7 +5,10 @@ import construct_editor.core.construct_editor as construct_editor import construct_editor.core.entries as entries -from construct_editor.core.model import ConstructEditorModel, IntegerFormat +from construct_editor.core.model import ( + ConstructEditorModel, + IntegerFormat, +) COPY_LABEL = "Copy" PASTE_LABEL = "Paste" @@ -15,6 +18,7 @@ INTFORMAT_DEC_LABEL = "Dec" INTFORMAT_HEX_LABEL = "Hex" + # ##################################################################################################################### # Context Menu ######################################################################################################## # ##################################################################################################################### @@ -26,7 +30,7 @@ class SeparatorMenuItem: @dataclasses.dataclass class ButtonMenuItem: label: str - shortcut: t.Optional[str] + shortcut: str | None enabled: bool callback: t.Callable[[], None] @@ -34,7 +38,7 @@ class ButtonMenuItem: @dataclasses.dataclass class CheckboxMenuItem: label: str - shortcut: t.Optional[str] + shortcut: str | None enabled: bool checked: bool callback: t.Callable[[bool], None] @@ -53,13 +57,7 @@ class SubmenuItem: subitems: t.List["MenuItem"] -MenuItem = t.Union[ - ButtonMenuItem, - SeparatorMenuItem, - CheckboxMenuItem, - RadioGroupMenuItems, - SubmenuItem, -] +MenuItem = ButtonMenuItem | SeparatorMenuItem | CheckboxMenuItem | RadioGroupMenuItems | SubmenuItem class ContextMenu: @@ -161,7 +159,6 @@ def _init_intformat(self): def _init_list_viewed_entries(self): submenu = SubmenuItem("List Viewed Items", []) for e in self.model.list_viewed_entries: - def on_remove_list_viewed_item(checked: bool): self.parent.disable_list_view(e) diff --git a/construct_editor/core/entries.py b/construct_editor/core/entries.py index 4cde882..f96b1f9 100644 --- a/construct_editor/core/entries.py +++ b/construct_editor/core/entries.py @@ -89,16 +89,16 @@ class ObjViewSettings_Timestamp: entry: "EntryTimestamp" -ObjViewSettings = t.Union[ - ObjViewSettings_Default, - ObjViewSettings_String, - ObjViewSettings_Integer, - ObjViewSettings_Flag, - ObjViewSettings_Bytes, - ObjViewSettings_Enum, - ObjViewSettings_FlagsEnum, - ObjViewSettings_Timestamp, -] +ObjViewSettings = ( + ObjViewSettings_Default + | ObjViewSettings_String + | ObjViewSettings_Integer + | ObjViewSettings_Flag + | ObjViewSettings_Bytes + | ObjViewSettings_Enum + | ObjViewSettings_FlagsEnum + | ObjViewSettings_Timestamp +) def _convert_restreamed(stream: cs.RestreamedBytesIO) -> io.BytesIO: @@ -109,7 +109,7 @@ def _convert_restreamed(stream: cs.RestreamedBytesIO) -> io.BytesIO: - `cs.BitsSwapped(cs.Bitwise(cs.GreedyRange(cs.Bit)))` """ - def reset_substream_recursively(stream: t.Union[io.BytesIO, cs.RestreamedBytesIO]): + def reset_substream_recursively(stream: io.BytesIO | cs.RestreamedBytesIO): if isinstance(stream, cs.RestreamedBytesIO): if stream.substream is None: raise RuntimeError( @@ -120,7 +120,7 @@ def reset_substream_recursively(stream: t.Union[io.BytesIO, cs.RestreamedBytesIO stream.seek(0) # check if there is already a cached version - bytes_io_stream: t.Optional[io.BytesIO] = getattr( + bytes_io_stream: io.BytesIO | None = getattr( stream, "_construct_bytes_io", None ) @@ -169,9 +169,9 @@ class ListIndexName(str): pass -NameType = t.Union[str, NameExcludedFromPath, ListIndexName] +NameType = str | NameExcludedFromPath | ListIndexName -PathType = t.List[t.Union[str, ListIndexName]] +PathType = t.List[str | ListIndexName] def create_path_str(path: PathType) -> str: @@ -197,7 +197,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Construct[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): self.model = model @@ -275,7 +275,7 @@ def obj_str(self) -> str: # default "obj_metadata" ################################################## @property - def obj_metadata(self) -> t.Optional[GuiMetaData]: + def obj_metadata(self) -> GuiMetaData | None: return get_gui_metadata(self.obj) # default "name" ########################################################## @@ -298,7 +298,7 @@ def typ_str(self) -> str: # default "subentries" #################################################### @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: return None # default "visible_row" ################################################### @@ -366,7 +366,7 @@ def path(self) -> PathType: return path def get_stream_infos( - self, child_stream: t.Optional[t.BinaryIO] = None + self, child_stream: t.BinaryIO | None = None ) -> t.List[StreamInfo]: """ Get infos about the current and parent streams. @@ -414,7 +414,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Subconstruct[Any, Any, Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -435,7 +435,7 @@ def typ_str(self) -> str: # pass throught "subentries" to subentry ################################## @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: return self.subentry.subentries # pass throught "obj_view_settings" to subentry ########################### @@ -457,7 +457,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Struct[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -471,7 +471,7 @@ def __init__( self._subentries.append(subentry) @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: return self._subentries @property @@ -525,7 +525,7 @@ def __init__( construct: t.Union[ "cs.Array[Any, Any, Any, Any]", "cs.GreedyRange[Any, Any, Any, Any]" ], - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -533,7 +533,7 @@ def __init__( self._subentries = [] @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: # get length of array try: array_len = len(self.obj) @@ -638,7 +638,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.IfThenElse[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -665,7 +665,7 @@ def __init__( self._subentry_else, ] - def _get_subentry(self) -> "Optional[EntryConstruct]": + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj if obj is None: @@ -699,7 +699,7 @@ def typ_str(self) -> str: return subentry.typ_str @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: subentry = self._get_subentry() if subentry is None: return self._subentries @@ -731,14 +731,14 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Switch[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) self._subentries: List[EntryConstruct] = [] self._subentry_cases: Dict[str, EntryConstruct] = {} - self._subentry_default: Optional[EntryConstruct] = None + self._subentry_default: EntryConstruct | None = None for key, value in self.construct.cases.items(): subentry_case = create_entry_from_construct( @@ -761,7 +761,7 @@ def __init__( ) self._subentries.append(self._subentry_default) - def _get_subentry(self) -> "Optional[EntryConstruct]": + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj if obj is None: @@ -795,7 +795,7 @@ def typ_str(self) -> str: return subentry.typ_str @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: subentry = self._get_subentry() if subentry is None: return self._subentries @@ -833,7 +833,7 @@ class FormatFieldFloat: class EntryFormatField(EntryConstruct): construct: "cs.FormatField[Any, Any]" - type_mapping: t.Dict[str, t.Union[FormatFieldInt, FormatFieldFloat]] = { + type_mapping: t.Dict[str, FormatFieldInt | FormatFieldFloat] = { ">B": FormatFieldInt("Int8ub", 8, False), ">H": FormatFieldInt("Int16ub", 16, False), ">L": FormatFieldInt("Int32ub", 32, False), @@ -874,7 +874,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.FormatField[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -920,7 +920,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.BytesInteger[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -966,7 +966,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.BitsInteger[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1002,7 +1002,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.StringEncoded[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) # type: ignore @@ -1025,7 +1025,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: t.Union["cs.Bytes[Any, Any]", "cs.Construct[bytes, bytes]"], - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1086,7 +1086,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Construct[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1105,7 +1105,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Seek", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1126,7 +1126,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Construct[None, None]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1147,7 +1147,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Const[Any, Any, Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1164,7 +1164,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Computed[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1188,7 +1188,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Subconstruct[Any, Any, Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1219,7 +1219,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.FocusedSeq", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1247,7 +1247,7 @@ def __init__( ) self._subentries[name] = subentry - def _get_subentry(self) -> "Optional[EntryConstruct]": + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj if obj is None: @@ -1279,7 +1279,7 @@ def typ_str(self) -> str: return subentry.typ_str @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: subentry = self._get_subentry() if subentry is None: return list(self._subentries.values()) @@ -1311,7 +1311,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Select", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1330,7 +1330,7 @@ def __init__( ) self._subentries[id(subentry.construct)] = subentry - def _get_subentry(self) -> "Optional[EntryConstruct]": + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj if obj is None: @@ -1367,7 +1367,7 @@ def typ_str(self) -> str: return subentry.typ_str @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: subentry = self._get_subentry() if subentry is None: return list(self._subentries.values()) @@ -1397,7 +1397,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.TimestampAdapter[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1418,7 +1418,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Subconstruct[Any, Any, Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1433,7 +1433,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.NullStripped[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1452,7 +1452,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.NullTerminated[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1469,7 +1469,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Checksum[Any, Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): # Don't access EntrySubconstruct's __init__() via super(), because "subcon" is no member of "cs.Checksum" @@ -1488,7 +1488,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Compressed[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1507,7 +1507,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Peek", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1520,7 +1520,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.RawCopy[Any, Any, Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1537,13 +1537,13 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cst.DataclassStruct[Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @property - def subentries(self) -> Optional[List["EntryConstruct"]]: + def subentries(self) -> List["EntryConstruct"] | None: subentries = super().subentries if (subentries is not None) and self.construct.reverse: return list(reversed(subentries)) @@ -1563,7 +1563,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.FormatField[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1591,7 +1591,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.Enum", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1658,7 +1658,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cs.FlagsEnum", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1722,7 +1722,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cst.TEnum[Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1781,7 +1781,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: "cst.TFlagsEnum[Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) @@ -1957,7 +1957,7 @@ def create_entry_from_construct( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], subcon: "cs.Construct[Any, Any]", - name: t.Optional[NameType], + name: NameType | None, docs: str, ) -> "EntryConstruct": diff --git a/construct_editor/core/model.py b/construct_editor/core/model.py index e20c5a8..9a5b04d 100644 --- a/construct_editor/core/model.py +++ b/construct_editor/core/model.py @@ -49,8 +49,8 @@ class ConstructEditorModel: """ def __init__(self): - self.root_entry: t.Optional["entries.EntryConstruct"] = None - self.root_obj: t.Optional[t.Any] = None + self.root_entry: "entries.EntryConstruct | None" = None + self.root_obj: t.Any | None = None # Modelwide flag, if hidden entries should be shown (hidden means starting with an underscore) self.hide_protected = True diff --git a/construct_editor/core/preprocessor.py b/construct_editor/core/preprocessor.py index bf09e8f..ff40a9f 100644 --- a/construct_editor/core/preprocessor.py +++ b/construct_editor/core/preprocessor.py @@ -51,7 +51,7 @@ def __init__(self, wrapped: t.Any, gui_metadata: GuiMetaData): ) -def get_gui_metadata(obj: t.Any) -> t.Optional[GuiMetaData]: +def get_gui_metadata(obj: t.Any) -> GuiMetaData | None: """Get the GUI metadata if they are available""" try: return getattr(obj, "__construct_editor_metadata__") diff --git a/construct_editor/gallery/__init__.py b/construct_editor/gallery/__init__.py index a482f8c..1d53228 100644 --- a/construct_editor/gallery/__init__.py +++ b/construct_editor/gallery/__init__.py @@ -1,7 +1,8 @@ import dataclasses -import construct as cs import typing as t +import construct as cs + @dataclasses.dataclass class GalleryItem: diff --git a/construct_editor/gallery/example_cmd_resp.py b/construct_editor/gallery/example_cmd_resp.py index 4d15d81..bbe8730 100644 --- a/construct_editor/gallery/example_cmd_resp.py +++ b/construct_editor/gallery/example_cmd_resp.py @@ -1,7 +1,9 @@ -import construct as cs -import construct_typed as cst import dataclasses import typing as t + +import construct as cs +import construct_typed as cst + from . import GalleryItem @@ -63,11 +65,7 @@ class RespData_Error(cst.DataclassMixin): CmdCode.Command2: cst.DataclassStruct(RespData_Command2), } -RespDataType = t.Union[ - bytes, - RespData_Command1, - RespData_Command2, -] +RespDataType = bytes | RespData_Command1 | RespData_Command2 class StatusCode(cst.EnumBase): @@ -131,5 +129,4 @@ class Response(cst.DataclassMixin): # ###################################################################################### import construct_editor.core.custom as custom - custom.add_custom_transparent_subconstruct(DefaultSized) diff --git a/construct_editor/gallery/example_ipstack.py b/construct_editor/gallery/example_ipstack.py index 37e626e..fa58b86 100644 --- a/construct_editor/gallery/example_ipstack.py +++ b/construct_editor/gallery/example_ipstack.py @@ -6,9 +6,10 @@ from construct import * # type: ignore from construct.lib import * # type: ignore + import construct_editor.core.custom as custom -from . import GalleryItem +from . import GalleryItem #=============================================================================== # layer 2, Ethernet diff --git a/construct_editor/gallery/example_pe32coff.py b/construct_editor/gallery/example_pe32coff.py index d0dfda4..f3c87f8 100644 --- a/construct_editor/gallery/example_pe32coff.py +++ b/construct_editor/gallery/example_pe32coff.py @@ -1,4 +1,5 @@ from construct import * # type: ignore + from . import GalleryItem docs = """ diff --git a/construct_editor/gallery/test_aligned.py b/construct_editor/gallery/test_aligned.py index c47c864..1a5d8b3 100644 --- a/construct_editor/gallery/test_aligned.py +++ b/construct_editor/gallery/test_aligned.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "before" / cs.Int8ub, diff --git a/construct_editor/gallery/test_array.py b/construct_editor/gallery/test_array.py index bfb6ebc..a2915c2 100644 --- a/construct_editor/gallery/test_array.py +++ b/construct_editor/gallery/test_array.py @@ -1,7 +1,9 @@ -import construct as cs -import construct_typed as cst import dataclasses import typing as t + +import construct as cs +import construct_typed as cst + from . import GalleryItem diff --git a/construct_editor/gallery/test_bits_swapped_bitwise.py b/construct_editor/gallery/test_bits_swapped_bitwise.py index ab9f4bb..5515aa4 100644 --- a/construct_editor/gallery/test_bits_swapped_bitwise.py +++ b/construct_editor/gallery/test_bits_swapped_bitwise.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.BitsSwapped(cs.Bitwise(cs.GreedyRange(cs.Bit))) diff --git a/construct_editor/gallery/test_bitwise.py b/construct_editor/gallery/test_bitwise.py index a587403..04f6de5 100644 --- a/construct_editor/gallery/test_bitwise.py +++ b/construct_editor/gallery/test_bitwise.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Bitwise(cs.GreedyRange(cs.Bit)) diff --git a/construct_editor/gallery/test_bytes_greedybytes.py b/construct_editor/gallery/test_bytes_greedybytes.py index aee7402..cc39979 100644 --- a/construct_editor/gallery/test_bytes_greedybytes.py +++ b/construct_editor/gallery/test_bytes_greedybytes.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "len" / cs.Int8ul, diff --git a/construct_editor/gallery/test_checksum.py b/construct_editor/gallery/test_checksum.py index 915cc02..677273b 100644 --- a/construct_editor/gallery/test_checksum.py +++ b/construct_editor/gallery/test_checksum.py @@ -1,7 +1,8 @@ import hashlib + import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "checksum_start" / cs.Tell, diff --git a/construct_editor/gallery/test_compressed.py b/construct_editor/gallery/test_compressed.py index 6a6c7d2..013803b 100644 --- a/construct_editor/gallery/test_compressed.py +++ b/construct_editor/gallery/test_compressed.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "compressed_bits" diff --git a/construct_editor/gallery/test_computed.py b/construct_editor/gallery/test_computed.py index 356ee7d..33c09f6 100644 --- a/construct_editor/gallery/test_computed.py +++ b/construct_editor/gallery/test_computed.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_const.py b/construct_editor/gallery/test_const.py index 30634cf..973c694 100644 --- a/construct_editor/gallery/test_const.py +++ b/construct_editor/gallery/test_const.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_dataclass_bit_struct.py b/construct_editor/gallery/test_dataclass_bit_struct.py index 9214562..57d8436 100644 --- a/construct_editor/gallery/test_dataclass_bit_struct.py +++ b/construct_editor/gallery/test_dataclass_bit_struct.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_dataclass_struct.py b/construct_editor/gallery/test_dataclass_struct.py index ae95a27..b6d543b 100644 --- a/construct_editor/gallery/test_dataclass_struct.py +++ b/construct_editor/gallery/test_dataclass_struct.py @@ -1,7 +1,9 @@ -import construct as cs -import construct_typed as cst import dataclasses import typing as t + +import construct as cs +import construct_typed as cst + from . import GalleryItem diff --git a/construct_editor/gallery/test_default.py b/construct_editor/gallery/test_default.py index 8d00af1..34c7876 100644 --- a/construct_editor/gallery/test_default.py +++ b/construct_editor/gallery/test_default.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_enum.py b/construct_editor/gallery/test_enum.py index f5239e8..838a54c 100644 --- a/construct_editor/gallery/test_enum.py +++ b/construct_editor/gallery/test_enum.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "brand" / cs.Enum(cs.Int8ul, Porsche=0, Audi=4, VW=7), diff --git a/construct_editor/gallery/test_fixedsized.py b/construct_editor/gallery/test_fixedsized.py index 7ae5a8f..cda2c7d 100644 --- a/construct_editor/gallery/test_fixedsized.py +++ b/construct_editor/gallery/test_fixedsized.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "choice" / cs.Int32ul, diff --git a/construct_editor/gallery/test_flag.py b/construct_editor/gallery/test_flag.py index 4d6ba0d..dff51a4 100644 --- a/construct_editor/gallery/test_flag.py +++ b/construct_editor/gallery/test_flag.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "flag0" / cs.Flag, diff --git a/construct_editor/gallery/test_flagsenum.py b/construct_editor/gallery/test_flagsenum.py index ab6e2e8..66dd5f0 100644 --- a/construct_editor/gallery/test_flagsenum.py +++ b/construct_editor/gallery/test_flagsenum.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "permissions" / cs.FlagsEnum(cs.Int8ul, R=4, W=2, X=1), diff --git a/construct_editor/gallery/test_greedyrange.py b/construct_editor/gallery/test_greedyrange.py index 1bee9c0..9075875 100644 --- a/construct_editor/gallery/test_greedyrange.py +++ b/construct_editor/gallery/test_greedyrange.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_ifthenelse.py b/construct_editor/gallery/test_ifthenelse.py index 21e6954..92a24bf 100644 --- a/construct_editor/gallery/test_ifthenelse.py +++ b/construct_editor/gallery/test_ifthenelse.py @@ -1,7 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses -import typing as t + from . import GalleryItem @@ -20,7 +21,7 @@ class Else(cst.DataclassMixin): else_4: int = cst.csfield(cs.Int8sb) choice: int = cst.csfield(cs.Int8ub) - if_then_else: t.Union[Then, Else] = cst.csfield( + if_then_else: Then | Else = cst.csfield( cs.IfThenElse( cs.this.choice == 0, cst.DataclassStruct(Then), cst.DataclassStruct(Else) ) diff --git a/construct_editor/gallery/test_ifthenelse_nested_switch.py b/construct_editor/gallery/test_ifthenelse_nested_switch.py index 19ecb37..6d0503e 100644 --- a/construct_editor/gallery/test_ifthenelse_nested_switch.py +++ b/construct_editor/gallery/test_ifthenelse_nested_switch.py @@ -1,7 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses -import typing as t + from . import GalleryItem @@ -20,7 +21,7 @@ class Else(cst.DataclassMixin): else_4: int = cst.csfield(cs.Int8sb) choice: int = cst.csfield(cs.Int8ub) - if_then_else: t.Union[Then, Else, bytes] = cst.csfield( + if_then_else: Then | Else | bytes = cst.csfield( cs.IfThenElse( cs.this.choice == 0, cs.Switch( diff --git a/construct_editor/gallery/test_nullstripped.py b/construct_editor/gallery/test_nullstripped.py index 0ef45fc..e23d59f 100644 --- a/construct_editor/gallery/test_nullstripped.py +++ b/construct_editor/gallery/test_nullstripped.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "null_stripped" / cs.NullStripped(cs.GreedyBytes, pad=b"\x00"), diff --git a/construct_editor/gallery/test_nullterminated.py b/construct_editor/gallery/test_nullterminated.py index 3c8f932..538cc82 100644 --- a/construct_editor/gallery/test_nullterminated.py +++ b/construct_editor/gallery/test_nullterminated.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "null_terminated" / cs.NullTerminated(cs.Int16ul, term=b"\x00"), diff --git a/construct_editor/gallery/test_padded.py b/construct_editor/gallery/test_padded.py index ddad64b..8119591 100644 --- a/construct_editor/gallery/test_padded.py +++ b/construct_editor/gallery/test_padded.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "padded" / cs.Padded(5, cs.Bytes(3)), diff --git a/construct_editor/gallery/test_padded_string.py b/construct_editor/gallery/test_padded_string.py index 6eff295..4dcf022 100644 --- a/construct_editor/gallery/test_padded_string.py +++ b/construct_editor/gallery/test_padded_string.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_pass.py b/construct_editor/gallery/test_pass.py index 1fd95e2..50fc8b1 100644 --- a/construct_editor/gallery/test_pass.py +++ b/construct_editor/gallery/test_pass.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "value1" / cs.Int8sb, diff --git a/construct_editor/gallery/test_pointer_peek_seek_tell.py b/construct_editor/gallery/test_pointer_peek_seek_tell.py index a736f19..9e9e751 100644 --- a/construct_editor/gallery/test_pointer_peek_seek_tell.py +++ b/construct_editor/gallery/test_pointer_peek_seek_tell.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "signature" / cs.Bytes(23), diff --git a/construct_editor/gallery/test_renamed.py b/construct_editor/gallery/test_renamed.py index 8490a65..093dbf7 100644 --- a/construct_editor/gallery/test_renamed.py +++ b/construct_editor/gallery/test_renamed.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_select_complex.py b/construct_editor/gallery/test_select_complex.py index 0af674f..1854f59 100644 --- a/construct_editor/gallery/test_select_complex.py +++ b/construct_editor/gallery/test_select_complex.py @@ -1,5 +1,4 @@ import dataclasses -import typing as t import construct as cs import construct_typed as cst @@ -24,7 +23,7 @@ class SmallImage(cst.DataclassMixin): @dataclasses.dataclass class Image(cst.DataclassMixin): is_big: int = cst.csfield(cs.Int8ub) - data: t.Union[BigImage, SmallImage] = cst.csfield( + data: BigImage | SmallImage = cst.csfield( cs.Select( cs.IfThenElse( condfunc=cs.this.is_big == 1, diff --git a/construct_editor/gallery/test_stringencodded.py b/construct_editor/gallery/test_stringencodded.py index 0c5429d..885883c 100644 --- a/construct_editor/gallery/test_stringencodded.py +++ b/construct_editor/gallery/test_stringencodded.py @@ -1,6 +1,8 @@ +from typing import Any, Dict + import construct as cs + from . import GalleryItem -from typing import Dict, Any ENCODDINGS = dict( ASCII="ascii", diff --git a/construct_editor/gallery/test_switch.py b/construct_editor/gallery/test_switch.py index 2637d5e..91f4795 100644 --- a/construct_editor/gallery/test_switch.py +++ b/construct_editor/gallery/test_switch.py @@ -1,6 +1,6 @@ import construct as cs -from . import GalleryItem +from . import GalleryItem constr = cs.Struct( "choice" diff --git a/construct_editor/gallery/test_switch_dataclass.py b/construct_editor/gallery/test_switch_dataclass.py index 8e9fd5f..64ec04d 100644 --- a/construct_editor/gallery/test_switch_dataclass.py +++ b/construct_editor/gallery/test_switch_dataclass.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_tenum.py b/construct_editor/gallery/test_tenum.py index 159eed6..409c0c2 100644 --- a/construct_editor/gallery/test_tenum.py +++ b/construct_editor/gallery/test_tenum.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_tflagsenum.py b/construct_editor/gallery/test_tflagsenum.py index 4f27151..0b5a8de 100644 --- a/construct_editor/gallery/test_tflagsenum.py +++ b/construct_editor/gallery/test_tflagsenum.py @@ -1,6 +1,8 @@ +import dataclasses + import construct as cs import construct_typed as cst -import dataclasses + from . import GalleryItem diff --git a/construct_editor/gallery/test_timestamp.py b/construct_editor/gallery/test_timestamp.py index 59598eb..ddfe33a 100644 --- a/construct_editor/gallery/test_timestamp.py +++ b/construct_editor/gallery/test_timestamp.py @@ -1,7 +1,9 @@ -import construct as cs -import construct_typed as cst import dataclasses + import arrow +import construct as cs +import construct_typed as cst + from . import GalleryItem diff --git a/construct_editor/main.py b/construct_editor/main.py index 9cbf240..07504ed 100644 --- a/construct_editor/main.py +++ b/construct_editor/main.py @@ -18,9 +18,9 @@ import construct_editor.gallery.test_compressed import construct_editor.gallery.test_computed import construct_editor.gallery.test_const -import construct_editor.gallery.test_default import construct_editor.gallery.test_dataclass_bit_struct import construct_editor.gallery.test_dataclass_struct +import construct_editor.gallery.test_default import construct_editor.gallery.test_enum import construct_editor.gallery.test_fixedsized import construct_editor.gallery.test_flag diff --git a/construct_editor/wx_widgets/wx_construct_editor.py b/construct_editor/wx_widgets/wx_construct_editor.py index d777f61..a8f0bcd 100644 --- a/construct_editor/wx_widgets/wx_construct_editor.py +++ b/construct_editor/wx_widgets/wx_construct_editor.py @@ -11,13 +11,13 @@ from construct_editor.core.entries import EntryConstruct from construct_editor.core.model import ConstructEditorColumn, ConstructEditorModel from construct_editor.wx_widgets.wx_context_menu import WxContextMenu +from construct_editor.wx_widgets.wx_exception_dialog import WxExceptionDialog from construct_editor.wx_widgets.wx_obj_view import ( WxObjEditor, WxObjRendererHelper, create_obj_editor, create_obj_renderer_helper, ) -from construct_editor.wx_widgets.wx_exception_dialog import WxExceptionDialog @dataclasses.dataclass @@ -34,8 +34,8 @@ class ValueFromEditorCtrl: class ObjectRenderer(dv.DataViewCustomRenderer): def __init__(self): super().__init__(varianttype="PyObject") - self.entry: t.Optional[EntryConstruct] = None - self.entry_renderer_helper: t.Optional[WxObjRendererHelper] = None + self.entry: EntryConstruct | None = None + self.entry_renderer_helper: WxObjRendererHelper | None = None self.EnableEllipsize(wx.ELLIPSIZE_END) def SetValue(self, value: EntryConstruct): @@ -105,7 +105,7 @@ def ActivateCell( model: dv.DataViewModel, item: dv.DataViewItem, col: int, - mouseEvent: t.Optional[wx.MouseEvent], + mouseEvent: wx.MouseEvent | None, ): if self.entry_renderer_helper is None: raise ValueError("`entry_renderer_helper` not set") @@ -312,7 +312,7 @@ def _init_gui(self): self._parse_error_info_bar.Bind( wx.EVT_BUTTON, self._parse_error_info_bar_btn_clicked, id=btn_id ) - self._parse_error_ex: t.Optional[Exception] = None + self._parse_error_ex: Exception | None = None vsizer.Add(self._parse_error_info_bar, 0, wx.EXPAND) self._build_error_info_bar = wx.InfoBar(self) @@ -321,7 +321,7 @@ def _init_gui(self): self._build_error_info_bar.Bind( wx.EVT_BUTTON, self._build_error_info_bar_btn_clicked, id=btn_id ) - self._build_error_ex: t.Optional[Exception] = None + self._build_error_ex: Exception | None = None vsizer.Add(self._build_error_info_bar, 0, wx.EXPAND) # create status bar @@ -354,9 +354,7 @@ def _init_gui(self): self._dvc_main_window.Bind(wx.EVT_MOTION, self._on_dvc_motion) self._dvc_main_window.Bind(wx.EVT_KEY_DOWN, self._on_dvc_key_down) self._dvc_main_window.Bind(wx.EVT_CHAR, self._on_dvc_char) - self._last_tooltip: t.Optional[ - t.Tuple[EntryConstruct, ConstructEditorColumn] - ] = None + self._last_tooltip: t.Tuple[EntryConstruct, ConstructEditorColumn] | None = None def reload(self): """ @@ -386,7 +384,7 @@ def reload(self): finally: self.Thaw() - def show_parse_error_message(self, msg: t.Optional[str], ex: t.Optional[Exception]): + def show_parse_error_message(self, msg: str | None, ex: Exception | None): """ Show an message to the user. """ @@ -396,7 +394,7 @@ def show_parse_error_message(self, msg: t.Optional[str], ex: t.Optional[Exceptio self._parse_error_ex = ex self._parse_error_info_bar.ShowMessage(msg, wx.ICON_WARNING) - def show_build_error_message(self, msg: t.Optional[str], ex: t.Optional[Exception]): + def show_build_error_message(self, msg: str | None, ex: Exception | None): """ Show an build error message to the user. """ @@ -413,7 +411,7 @@ def show_status(self, path_info: str, bytes_info: str): self._status_bar.SetStatusText(path_info, 0) self._status_bar.SetStatusText(bytes_info, 1) - def get_selected_entry(self) -> t.Optional[EntryConstruct]: + def get_selected_entry(self) -> EntryConstruct | None: """ Get the currently selected entry (or None if nothing is selected). """ @@ -581,7 +579,7 @@ def _on_dvc_right_clicked(self, event: dv.DataViewEvent): Then a context menu is created """ item = event.GetItem() - entry: t.Optional["EntryConstruct"] + entry: "EntryConstruct | None" if item.ID is not None: entry = self._model.dvc_item_to_entry(item) else: diff --git a/construct_editor/wx_widgets/wx_construct_hex_editor.py b/construct_editor/wx_widgets/wx_construct_hex_editor.py index ccbc7a3..12f7f87 100644 --- a/construct_editor/wx_widgets/wx_construct_hex_editor.py +++ b/construct_editor/wx_widgets/wx_construct_hex_editor.py @@ -50,7 +50,7 @@ def __init__( self.Initialize(panel) - self.sub_panel: t.Optional["HexEditorPanel"] = None + self.sub_panel: "HexEditorPanel | None" = None def clear_sub_panels(self): """Clears all sub-panels recursivly""" @@ -257,7 +257,7 @@ def _convert_struct_to_binary(self): self.Thaw() self._converting = False - def _on_entry_selected(self, entry: t.Optional[EntryConstruct]): + def _on_entry_selected(self, entry: EntryConstruct | None): try: self.Freeze() self.hex_panel.clear_sub_panels() diff --git a/construct_editor/wx_widgets/wx_exception_dialog.py b/construct_editor/wx_widgets/wx_exception_dialog.py index 00b5a1b..461d113 100644 --- a/construct_editor/wx_widgets/wx_exception_dialog.py +++ b/construct_editor/wx_widgets/wx_exception_dialog.py @@ -10,12 +10,12 @@ class ExceptionInfo: etype: t.Type[BaseException] value: BaseException - trace: t.Optional[TracebackType] + trace: TracebackType | None class WxExceptionDialog(wx.Dialog): def __init__( - self, parent, title: str, exception: t.Union[ExceptionInfo, BaseException] + self, parent, title: str, exception: ExceptionInfo | BaseException ): wx.Dialog.__init__( self, diff --git a/construct_editor/wx_widgets/wx_hex_editor.py b/construct_editor/wx_widgets/wx_hex_editor.py index f56c2f2..745e9ec 100644 --- a/construct_editor/wx_widgets/wx_hex_editor.py +++ b/construct_editor/wx_widgets/wx_hex_editor.py @@ -606,7 +606,7 @@ class ContextMenuItem: # None = option # True = toggle selected # False = toggle unselected - toggle_state: t.Optional[bool] + toggle_state: bool | None enabled: bool @@ -631,7 +631,7 @@ def __init__( self._table = table self._binary_data = binary_data self.read_only = read_only - self.on_selection_changed: "CallbackList[[int, t.Optional[int]]]" = ( + self.on_selection_changed: "CallbackList[[int, int | None]]" = ( CallbackList() ) @@ -665,7 +665,7 @@ def __init__( self.refresh() - self._selection: t.Tuple[t.Optional[int], t.Optional[int]] = (None, None) + self._selection: t.Tuple[int | None, int | None] = (None, None) def refresh(self): """ @@ -1136,7 +1136,7 @@ def _on_cell_right_click(self, event: Grid.GridEvent): def build_context_menu( self, - ) -> t.List[t.Optional[ContextMenuItem]]: + ) -> t.List[ContextMenuItem | None]: """Build the context menu. Can be overridden.""" return [ @@ -1198,7 +1198,7 @@ def __init__( self, parent, binary: bytes = b"", - format: t.Optional[HexEditorFormat] = None, + format: HexEditorFormat | None = None, read_only: bool = False, bitwiese: bool = False, ): @@ -1246,7 +1246,7 @@ def _on_binary_changed(self, binary_data: HexEditorBinaryData): self._status_bar.SetStatusText(msg, 0) self.refresh() - def _on_selection_changed(self, idx1: int, idx2: t.Optional[int]): + def _on_selection_changed(self, idx1: int, idx2: int | None): if idx2 is None: msg = f"Selection: {idx1:n}" else: @@ -1305,7 +1305,7 @@ def on_binary_changed(self) -> "CallbackList[[HexEditorBinaryData]]": # Property: on_binary_changed ############################################# @property - def on_selection_changed(self) -> "CallbackList[[int, t.Optional[int]]]": + def on_selection_changed(self) -> "CallbackList[[int, int | None]]": return self._grid.on_selection_changed diff --git a/construct_editor/wx_widgets/wx_obj_view.py b/construct_editor/wx_widgets/wx_obj_view.py index cbae980..1114b0a 100644 --- a/construct_editor/wx_widgets/wx_obj_view.py +++ b/construct_editor/wx_widgets/wx_obj_view.py @@ -326,15 +326,15 @@ def _on_kill_focus(self, event): evt_handler.ProcessEvent(event) -WxObjEditor = t.Union[ - WxObjEditor_Default, - WxObjEditor_String, - WxObjEditor_Integer, - WxObjEditor_Bytes, - WxObjEditor_Enum, - WxObjEditor_FlagsEnum, - WxObjEditor_Timestamp, -] +WxObjEditor = ( + WxObjEditor_Default + | WxObjEditor_String + | WxObjEditor_Integer + | WxObjEditor_Bytes + | WxObjEditor_Enum + | WxObjEditor_FlagsEnum + | WxObjEditor_Timestamp +) # ##################################################################################################################### @@ -401,7 +401,7 @@ def activate_cell( model: dv.DataViewModel, item: dv.DataViewItem, col: int, - mouse_event: t.Optional[wx.MouseEvent], + mouse_event: wx.MouseEvent | None, ): return False @@ -446,7 +446,7 @@ def activate_cell( model: dv.DataViewModel, item: dv.DataViewItem, col: int, - mouse_event: t.Optional[wx.MouseEvent], + mouse_event: wx.MouseEvent | None, ): # see wxWidgets: wxDataViewToggleRenderer::WXActivateCell @@ -469,10 +469,7 @@ def activate_cell( return True -WxObjRendererHelper = t.Union[ - WxObjRendererHelper_Default, - WxObjRendererHelper_Flag, -] +WxObjRendererHelper = WxObjRendererHelper_Default | WxObjRendererHelper_Flag def create_obj_renderer_helper(settings: ObjViewSettings) -> WxObjRendererHelper: diff --git a/construct_editor/wx_widgets/wx_python_code_editor.py b/construct_editor/wx_widgets/wx_python_code_editor.py index fac38f5..5a8f3e4 100644 --- a/construct_editor/wx_widgets/wx_python_code_editor.py +++ b/construct_editor/wx_widgets/wx_python_code_editor.py @@ -1,8 +1,8 @@ #!/usr/bin/env python import keyword - import sys + import wx import wx.stc as stc diff --git a/doc/screenshot_scripts/bitwise.py b/doc/screenshot_scripts/bitwise.py index 0702f16..4778769 100644 --- a/doc/screenshot_scripts/bitwise.py +++ b/doc/screenshot_scripts/bitwise.py @@ -3,7 +3,6 @@ from doc.screenshot_scripts._helper import ScreenshotFrame - class Frame(ScreenshotFrame): screenshot_name = "bitwise" diff --git a/pyproject.toml b/pyproject.toml index 2c0548c..8e8449f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -177,8 +177,12 @@ output-format = "concise" # "full" | "concise" | "grouped" | "json" | "junit" | [tool.ruff.lint] allowed-confusables = ["×", "–", "‘", "’"] - -# select = [] Use Default ruleset, cp. https://docs.astral.sh/ruff/rules/ +select = [ + "F", + "I", + "UP007", + "UP045", +] # These warnings should be activated as "error" in the future, but for now we don't want to refactor the entire codebase right now. ignore = [ From 02f01d16b75b089c2da5da80b665191d142f204d Mon Sep 17 00:00:00 2001 From: "Robin.Schmidt" Date: Mon, 29 Jun 2026 10:18:44 +0200 Subject: [PATCH 2/7] Fixed invalid-type-arguments. --- construct_editor/core/entries.py | 10 +++++----- pyproject.toml | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/construct_editor/core/entries.py b/construct_editor/core/entries.py index f96b1f9..4e6337b 100644 --- a/construct_editor/core/entries.py +++ b/construct_editor/core/entries.py @@ -515,7 +515,7 @@ def on_collapse_children_clicked(): # EntryArray ########################################################################################################## class EntryArray(EntrySubconstruct): construct: t.Union[ - "cs.Array[Any, Any, Any, Any]", "cs.GreedyRange[Any, Any, Any, Any]" + "cs.Array[Any, Any]", "cs.GreedyRange[Any, Any]" ] def __init__( @@ -523,7 +523,7 @@ def __init__( model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], construct: t.Union[ - "cs.Array[Any, Any, Any, Any]", "cs.GreedyRange[Any, Any, Any, Any]" + "cs.Array[Any, Any]", "cs.GreedyRange[Any, Any]" ], name: NameType | None, docs: str, @@ -1146,7 +1146,7 @@ def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.Const[Any, Any, Any, Any]", + construct: "cs.Const[Any, Any]", name: NameType | None, docs: str, ): @@ -1163,7 +1163,7 @@ def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.Computed[Any, Any]", + construct: "cs.Computed[Any]", name: NameType | None, docs: str, ): @@ -1519,7 +1519,7 @@ def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.RawCopy[Any, Any, Any, Any]", + construct: "cs.RawCopy[Any, Any]", name: NameType | None, docs: str, ): diff --git a/pyproject.toml b/pyproject.toml index 8e8449f..aa29df4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -162,7 +162,6 @@ exclude = [ invalid-argument-type = "ignore" invalid-assignment = "ignore" invalid-method-override = "ignore" -invalid-type-arguments = "ignore" unresolved-attribute = "ignore" unused-type-ignore-comment = "ignore" From e9cf206dfbae788f32aa3d383a8a9d344d8f782a Mon Sep 17 00:00:00 2001 From: "Robin.Schmidt" Date: Mon, 29 Jun 2026 10:55:02 +0200 Subject: [PATCH 3/7] Fixed invalid-assignment. --- construct_editor/gallery/test_computed.py | 15 ++++++++++----- construct_editor/main.py | 4 ++-- construct_editor/wx_widgets/wx_hex_editor.py | 2 +- pyproject.toml | 1 - 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/construct_editor/gallery/test_computed.py b/construct_editor/gallery/test_computed.py index 33c09f6..8d93965 100644 --- a/construct_editor/gallery/test_computed.py +++ b/construct_editor/gallery/test_computed.py @@ -8,11 +8,16 @@ @dataclasses.dataclass class ComputedTest(cst.DataclassMixin): - type_int: int | None = cst.csfield_noinit(cs.Computed(lambda ctx: 50)) - type_float: float | None = cst.csfield_noinit(cs.Computed(lambda ctx: 80.0)) - type_bool: bool | None = cst.csfield_noinit(cs.Computed(lambda ctx: True)) - type_bytes: bytes | None = cst.csfield_noinit(cs.Computed(lambda ctx: bytes([0x00, 0xAB]))) - type_bytearray: bytearray | None = cst.csfield_noinit(cs.Computed(lambda ctx: bytearray([0x00, 0xAB, 0xFF]))) + type_int_const: int = cst.csfield(cs.Computed(50)) + type_int_lambda: int = cst.csfield(cs.Computed(lambda ctx: 50)) + type_float_const: float = cst.csfield(cs.Computed(80.0)) + type_float_lambda: float = cst.csfield(cs.Computed(lambda ctx: 80.0)) + type_bool_const: bool = cst.csfield(cs.Computed(True)) + type_bool_lambda: bool = cst.csfield(cs.Computed(lambda ctx: True)) + type_bytes_const: bytes = cst.csfield(cs.Computed(bytes([0x00, 0xAB]))) + type_bytes_lambda: bytes = cst.csfield(cs.Computed(lambda ctx: bytes([0x00, 0xAB]))) + type_bytearray_const: bytearray = cst.csfield(cs.Computed(bytearray([0x00, 0xAB, 0xFF]))) + type_bytearray_lambda: bytearray = cst.csfield(cs.Computed(lambda ctx: bytearray([0x00, 0xAB, 0xFF]))) constr = cst.DataclassStruct(ComputedTest) diff --git a/construct_editor/main.py b/construct_editor/main.py index 07504ed..31aa410 100644 --- a/construct_editor/main.py +++ b/construct_editor/main.py @@ -68,13 +68,13 @@ def __init__(self, *args, **kwargs): self.status_bar: wx.StatusBar = self.CreateStatusBar() -def on_uncaught_exception(etype: t.Type[BaseException], value: BaseException, trace: TracebackType | None): +def on_uncaught_exception(etype: t.Type[BaseException], value: BaseException, trace: TracebackType | None) -> None: """ Handler for all unhandled exceptions. :param etype: the exception type (`SyntaxError`, `ZeroDivisionError`, etc...); :param value: the exception error message; - :param trace: the traceback header, if any (otherwise, it prints the standard Python header: ``Traceback (most recent call last)``. + :param trace: the traceback header, if any (otherwise, it prints the standard Python header: ``Traceback (most recent call last)``). """ with WxExceptionDialog(None, "Uncaught Exception...", ExceptionInfo(etype, value, trace)) as dial: dial.ShowModal() diff --git a/construct_editor/wx_widgets/wx_hex_editor.py b/construct_editor/wx_widgets/wx_hex_editor.py index 745e9ec..46a2656 100644 --- a/construct_editor/wx_widgets/wx_hex_editor.py +++ b/construct_editor/wx_widgets/wx_hex_editor.py @@ -1320,7 +1320,7 @@ def __init__(self, parent, title): # Create an instance of our model... self.hex_editor = WxHexEditor(self) - self.hex_editor.binary = bytearray(500) + self.hex_editor.binary = bytes(500) self.Show(True) diff --git a/pyproject.toml b/pyproject.toml index aa29df4..747f012 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -160,7 +160,6 @@ exclude = [ # Valid values: "error", "warn", "ignore" [tool.ty.rules] invalid-argument-type = "ignore" -invalid-assignment = "ignore" invalid-method-override = "ignore" unresolved-attribute = "ignore" unused-type-ignore-comment = "ignore" From d4e9eb2614a8516cbb8aa31dbae66e3cdbab8cc8 Mon Sep 17 00:00:00 2001 From: "Robin.Schmidt" Date: Mon, 29 Jun 2026 11:16:24 +0200 Subject: [PATCH 4/7] Fixed Pyright errors "E711: Comparison to `None` should be `cond is None`", "E712: Avoid equality comparisons to `True`", "F841: Local variable `...` is assigned but never used" --- construct_editor/core/model.py | 2 +- construct_editor/core/preprocessor.py | 2 +- construct_editor/gallery/example_cmd_resp.py | 2 +- construct_editor/wx_widgets/wx_hex_editor.py | 51 ++++++++++---------- pyproject.toml | 4 -- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/construct_editor/core/model.py b/construct_editor/core/model.py index 9a5b04d..4463915 100644 --- a/construct_editor/core/model.py +++ b/construct_editor/core/model.py @@ -90,7 +90,7 @@ def get_children( for subentry in entry.subentries: name = subentry.name - if (self.hide_protected == True) and (name.startswith("_") or name == ""): + if self.hide_protected and (name.startswith("_") or name == ""): subentry.visible_row = False continue diff --git a/construct_editor/core/preprocessor.py b/construct_editor/core/preprocessor.py index ff40a9f..066677e 100644 --- a/construct_editor/core/preprocessor.py +++ b/construct_editor/core/preprocessor.py @@ -122,7 +122,7 @@ def _parse(self, stream, context, path): return add_gui_metadata(obj, gui_metadata) def _build(self, obj, stream, context, path): - buildret = self.subcon._build(obj, stream, context, path) # type: ignore + _buildret = self.subcon._build(obj, stream, context, path) return obj # passthrought attribute access diff --git a/construct_editor/gallery/example_cmd_resp.py b/construct_editor/gallery/example_cmd_resp.py index bbe8730..e25d843 100644 --- a/construct_editor/gallery/example_cmd_resp.py +++ b/construct_editor/gallery/example_cmd_resp.py @@ -127,6 +127,6 @@ class Response(cst.DataclassMixin): # ###################################################################################### # ################## Adding new constructs to construct-editor ######################### # ###################################################################################### -import construct_editor.core.custom as custom +import construct_editor.core.custom as custom # noqa: E402 custom.add_custom_transparent_subconstruct(DefaultSized) diff --git a/construct_editor/wx_widgets/wx_hex_editor.py b/construct_editor/wx_widgets/wx_hex_editor.py index 46a2656..0de7776 100644 --- a/construct_editor/wx_widgets/wx_hex_editor.py +++ b/construct_editor/wx_widgets/wx_hex_editor.py @@ -243,8 +243,8 @@ def GetAttr(self, row, col, kind): byte_idx = self.get_byte_idx(row, col) selected = False - for sel in self.selections: - if sel[0] <= byte_idx < sel[1]: + for sel0, sel1 in self.selections: + if sel0 <= byte_idx < sel1: selected = True break @@ -775,20 +775,20 @@ def _on_range_selecting_mouse(self, event): def _on_range_selecting_keyboard(self, row_diff: int = 0, col_diff: int = 0): """Change selection from the keyboard""" - sel = self._selection - if sel[0] is None: + sel0, sel1 = self._selection + if sel0 is None: return # nothing is currently selected cursor_row, cursor_col = self.GetGridCursorCoords() cursor_idx = self._table.get_byte_idx(cursor_row, cursor_col) - if sel[1] is None: + if sel1 is None: other_idx = cursor_idx else: - if sel[0] == cursor_idx: - other_idx = sel[1] + if sel0 == cursor_idx: + other_idx = sel1 else: - other_idx = sel[0] + other_idx = sel0 cursor_row += row_diff if cursor_row < 0: @@ -865,17 +865,16 @@ def _remove_selection(self) -> bool: if self.read_only is True: return False - sel = self._selection - if sel[0] is None: + sel0, sel1 = self._selection + if sel0 is None: return False - if sel[1] == None: + if sel1 is None: length = 1 else: - length = sel[1] - sel[0] + 1 - - byts = self._binary_data.remove_range(sel[0], length) + length = sel1 - sel0 + 1 + self._binary_data.remove_range(sel0, length) self.ClearSelection() self._selection = (None, None) @@ -899,11 +898,11 @@ def _insert_byte_at_selection(self) -> bool: if self.read_only is True: return False - sel = self._selection - if sel[0] is None: + sel0, _ = self._selection + if sel0 is None: return False - self._binary_data.insert_range(sel[0], b"\x00") + self._binary_data.insert_range(sel0, b"\x00") self._on_range_selecting_keyboard() return True @@ -915,16 +914,16 @@ def _copy_selection(self) -> bool: - true if copy is okay - false if an error occured """ - sel = self._selection - if sel[0] is None: + sel0, sel1 = self._selection + if sel0 is None: return False - if sel[1] == None: + if sel1 is None: length = 1 else: - length = sel[1] - sel[0] + 1 + length = sel1 - sel0 + 1 - byts = self._binary_data.get_range(sel[0], length) + byts = self._binary_data.get_range(sel0, length) if wx.TheClipboard.Open(): byts_str = byts.hex(" ") @@ -1108,11 +1107,11 @@ def _on_cell_right_click(self, event: Grid.GridEvent): """Show context menu""" # Check if the click is inside the current selection. # If not, select the current cell - sel = self._selection + sel0, sel1 = self._selection select_cell = True - if sel[0] is not None and sel[1] is not None: + if sel0 is not None and sel1 is not None: idx = self._table.get_byte_idx(event.GetRow(), event.GetCol()) - if sel[0] <= idx <= sel[1]: + if sel0 <= idx <= sel1: select_cell = False if select_cell: @@ -1123,7 +1122,7 @@ def _on_cell_right_click(self, event: Grid.GridEvent): if menu is None: popup_menu.AppendSeparator() continue - if menu.toggle_state != None: # checkbox boolean state + if menu.toggle_state is not None: # checkbox boolean state item: wx.MenuItem = popup_menu.AppendCheckItem(menu.wx_id, menu.name) item.Check(menu.toggle_state) else: diff --git a/pyproject.toml b/pyproject.toml index 747f012..181a23a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -184,12 +184,8 @@ select = [ # These warnings should be activated as "error" in the future, but for now we don't want to refactor the entire codebase right now. ignore = [ - "E402", # Module level import not at top of file - "E711", # Comparison to `None` should be `cond is None` - "E712", # Avoid equality comparisons to `True` "F403", # `from ... import *` used; unable to detect undefined names "F405", # `...` may be undefined, or defined from star imports - "F841", # Local variable `...` is assigned to but never used ] [tool.poe.tasks.test] From 99673e9cd0e510648e1d947edb7649a0f202497c Mon Sep 17 00:00:00 2001 From: "Robin.Schmidt" Date: Tue, 21 Jul 2026 17:27:36 +0200 Subject: [PATCH 5/7] Pyright fixes --- construct_editor/core/construct_editor.py | 10 +- construct_editor/core/entries.py | 139 +++++++++++------- construct_editor/core/preprocessor.py | 10 +- construct_editor/gallery/example_cmd_resp.py | 2 +- construct_editor/gallery/example_ipstack.py | 13 +- construct_editor/gallery/test_checksum.py | 10 +- construct_editor/main.py | 16 +- .../wx_widgets/wx_construct_editor.py | 36 ++--- .../wx_widgets/wx_construct_hex_editor.py | 33 ++--- construct_editor/wx_widgets/wx_hex_editor.py | 28 ++-- construct_editor/wx_widgets/wx_obj_view.py | 8 +- .../wx_widgets/wx_python_code_editor.py | 18 +-- pyproject.toml | 23 +-- 13 files changed, 196 insertions(+), 150 deletions(-) diff --git a/construct_editor/core/construct_editor.py b/construct_editor/core/construct_editor.py index 9c2ac32..647977d 100644 --- a/construct_editor/core/construct_editor.py +++ b/construct_editor/core/construct_editor.py @@ -11,7 +11,7 @@ class ConstructEditor: - def __init__(self, construct: cs.Construct, model: ConstructEditorModel): + def __init__(self, construct: cs.Construct[t.Any, t.Any], model: ConstructEditorModel): self._model = model self.change_construct(construct) @@ -78,7 +78,7 @@ def _put_to_clipboard(self, txt: str): """ @abc.abstractmethod - def _get_from_clipboard(self): + def _get_from_clipboard(self) -> str | None: """ Get text from the clipboard. @@ -113,7 +113,7 @@ def paste_entry_value_from_clipboard(self, entry: "entries.EntryConstruct"): # self.model.set_value(txt, entry, ConstructEditorColumn.Value) # self.on_root_obj_changed.fire(self.root_obj) - def change_construct(self, constr: cs.Construct) -> None: + def change_construct(self, constr: cs.Construct[t.Any, t.Any]) -> None: """ Change the construct format, that is used for building/parsing. """ @@ -309,14 +309,14 @@ def is_list_view_enabled(self, entry: "entries.EntryConstruct") -> bool: return False @property - def construct(self) -> cs.Construct: + def construct(self) -> cs.Construct[t.Any, t.Any]: """ Construct that is used for displaying. """ return self._construct @construct.setter - def construct(self, constr: cs.Construct): + def construct(self, constr: cs.Construct[t.Any, t.Any]): self.change_construct(constr) @property diff --git a/construct_editor/core/entries.py b/construct_editor/core/entries.py index 4e6337b..6cd5c49 100644 --- a/construct_editor/core/entries.py +++ b/construct_editor/core/entries.py @@ -450,13 +450,11 @@ def modify_context_menu(self, menu: ContextMenu): # EntryStruct ######################################################################################################### class EntryStruct(EntryConstruct): - construct: "cs.Struct[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.Struct[Any, Any]", + construct: "cs.Struct", name: NameType | None, docs: str, ): @@ -470,6 +468,10 @@ def __init__( subentry = create_entry_from_construct(model, self, subcon, None, "") self._subentries.append(subentry) + @property + def construct(self) -> "cs.Struct": + return t.cast("cs.Struct", self._construct) + @property def subentries(self) -> List["EntryConstruct"] | None: return self._subentries @@ -514,17 +516,11 @@ def on_collapse_children_clicked(): # EntryArray ########################################################################################################## class EntryArray(EntrySubconstruct): - construct: t.Union[ - "cs.Array[Any, Any]", "cs.GreedyRange[Any, Any]" - ] - def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: t.Union[ - "cs.Array[Any, Any]", "cs.GreedyRange[Any, Any]" - ], + construct: "cs.Array[Any, Any] | cs.GreedyRange[Any, Any]", name: NameType | None, docs: str, ): @@ -532,6 +528,10 @@ def __init__( self._subentries = [] + @property + def construct(self) -> "cs.Array[Any, Any] | cs.GreedyRange[Any, Any]": + return t.cast("cs.Array[Any, Any] | cs.GreedyRange[Any, Any]", self._construct) + @property def subentries(self) -> List["EntryConstruct"] | None: # get length of array @@ -631,8 +631,6 @@ def on_menu_item_clicked(checked: bool): # EntryIfThenElse ##################################################################################################### class EntryIfThenElse(EntryConstruct): - construct: "cs.IfThenElse[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -665,6 +663,10 @@ def __init__( self._subentry_else, ] + @property + def construct(self) -> "cs.IfThenElse[Any, Any]": + return t.cast("cs.IfThenElse[Any, Any]", self._construct) + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj @@ -724,8 +726,6 @@ def modify_context_menu(self, menu: ContextMenu): # EntrySwitch ######################################################################################################### class EntrySwitch(EntryConstruct): - construct: "cs.Switch[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -751,7 +751,7 @@ def __init__( self._subentry_cases[key] = subentry_case self._subentries.append(subentry_case) - if self.construct.default is not None: + if self.construct.default is not None: # type: ignore[reportUnnecessaryComparison] self._subentry_default = create_entry_from_construct( self.model, self, @@ -761,6 +761,10 @@ def __init__( ) self._subentries.append(self._subentry_default) + @property + def construct(self) -> "cs.Switch[Any, Any]": + return t.cast("cs.Switch[Any, Any]", self._construct) + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj @@ -832,7 +836,6 @@ class FormatFieldFloat: class EntryFormatField(EntryConstruct): - construct: "cs.FormatField[Any, Any]" type_mapping: t.Dict[str, FormatFieldInt | FormatFieldFloat] = { ">B": FormatFieldInt("Int8ub", 8, False), ">H": FormatFieldInt("Int16ub", 16, False), @@ -884,6 +887,10 @@ def __init__( if construct.fmtstr in self.type_mapping: self.type_infos = self.type_mapping[construct.fmtstr] + @property + def construct(self) -> "cs.FormatField[Any, Any]": + return t.cast("cs.FormatField[Any, Any]", self._construct) + @property def obj_view_settings(self) -> ObjViewSettings: if isinstance(self.type_infos, FormatFieldInt): @@ -913,18 +920,20 @@ def typ_str(self) -> str: # EntryBytesInteger ################################################################################################### class EntryBytesInteger(EntryConstruct): - construct: "cs.BytesInteger[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.BytesInteger[Any, Any]", + construct: "cs.BytesInteger", name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.BytesInteger": + return t.cast("cs.BytesInteger", self._construct) + @property def typ_str(self) -> str: if self.construct.length == 3: @@ -959,18 +968,20 @@ def obj_view_settings(self) -> ObjViewSettings: # EntryBitsInteger #################################################################################################### class EntryBitsInteger(EntryConstruct): - construct: "cs.BitsInteger[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.BitsInteger[Any, Any]", + construct: "cs.BitsInteger", name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.BitsInteger": + return t.cast("cs.BitsInteger", self._construct) + @property def typ_str(self) -> str: # change default row infos @@ -1001,7 +1012,7 @@ def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.StringEncoded[Any, Any]", + construct: "cs.StringEncoded", name: NameType | None, docs: str, ): @@ -1018,19 +1029,21 @@ def obj_view_settings(self) -> ObjViewSettings: # EntryBytes ########################################################################################################## class EntryBytes(EntryConstruct): - construct: t.Union["cs.Bytes[Any, Any]", "cs.Construct[bytes, bytes]"] - def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: t.Union["cs.Bytes[Any, Any]", "cs.Construct[bytes, bytes]"], + construct: "cs.Bytes | cs.Construct[bytes, bytes]", name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) self.ascii_view = False + @property + def construct(self) -> "cs.Bytes | cs.Construct[bytes, bytes]": + return t.cast("cs.Bytes | cs.Construct[bytes, bytes]", self._construct) + @property def obj_str(self) -> str: try: @@ -1098,8 +1111,6 @@ def typ_str(self) -> str: # EntrySeek ########################################################################################################### class EntrySeek(EntryConstruct): - construct: "cs.Seek" - def __init__( self, model: "model.ConstructEditorModel", @@ -1110,6 +1121,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.Seek": + return t.cast("cs.Seek", self._construct) + @property def typ_str(self) -> str: return "Seek" @@ -1212,8 +1227,6 @@ def on_default_clicked(): # EntryFocusedSeq ################################################################################################### class EntryFocusedSeq(EntryConstruct): - construct: "cs.FocusedSeq" - def __init__( self, model: "model.ConstructEditorModel", @@ -1247,6 +1260,10 @@ def __init__( ) self._subentries[name] = subentry + @property + def construct(self) -> "cs.FocusedSeq": + return t.cast("cs.FocusedSeq", self._construct) + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj @@ -1304,8 +1321,6 @@ def modify_context_menu(self, menu: ContextMenu): # EntrySelect ################################################################################################### class EntrySelect(EntryConstruct): - construct: "cs.Select" - def __init__( self, model: "model.ConstructEditorModel", @@ -1330,6 +1345,10 @@ def __init__( ) self._subentries[id(subentry.construct)] = subentry + @property + def construct(self) -> "cs.Select": + return t.cast("cs.Select", self._construct) + def _get_subentry(self) -> "EntryConstruct | None": """Evaluate the conditional function to detect the type of the subentry""" obj = self.obj @@ -1426,8 +1445,6 @@ def __init__( # EntryNullStripped ################################################################################################### class EntryNullStripped(EntrySubconstruct): - construct: "cs.NullStripped[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -1438,6 +1455,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.NullStripped[Any, Any]": + return t.cast("cs.NullStripped[Any, Any]", self._construct) + @property def typ_str(self) -> str: return f"NullStripped[{self.subentry.typ_str}, Pad={self.construct.pad}]" @@ -1445,8 +1466,6 @@ def typ_str(self) -> str: # EntryNullTerminated ################################################################################################# class EntryNullTerminated(EntrySubconstruct): - construct: "cs.NullTerminated[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -1457,6 +1476,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.NullTerminated[Any, Any]": + return t.cast("cs.NullTerminated[Any, Any]", self._construct) + @property def typ_str(self) -> str: return f"NullTerminated[{self.subentry.typ_str}, Term={self.construct.term}]" @@ -1500,18 +1523,20 @@ def typ_str(self) -> str: # EntryPeek ########################################################################################################### class EntryPeek(EntrySubconstruct): - construct: "cs.Peek" - def __init__( self, model: "model.ConstructEditorModel", parent: Optional["EntryConstruct"], - construct: "cs.Peek", + construct: "cs.Peek[Any, Any]", name: NameType | None, docs: str, ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.Peek[Any, Any]": + return t.cast("cs.Peek[Any, Any]", self._construct) + # EntryRawCopy ####################################################################################################### class EntryRawCopy(EntrySubconstruct): @@ -1530,8 +1555,6 @@ def __init__( # EntryDataclassStruct ################################################################################################ class EntryDataclassStruct(EntrySubconstruct): - construct: "cst.DataclassStruct[Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -1542,6 +1565,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cst.DataclassStruct[Any]": + return t.cast("cst.DataclassStruct[Any]", self._construct) + @property def subentries(self) -> List["EntryConstruct"] | None: subentries = super().subentries @@ -1556,8 +1583,6 @@ def typ_str(self) -> str: # EntryFlag #################################################################################################### class EntryFlag(EntryConstruct): - construct: "cs.FormatField[Any, Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -1568,6 +1593,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.FormatField[Any, Any]": + return t.cast("cs.FormatField[Any, Any]", self._construct) + @property def obj_view_settings(self) -> ObjViewSettings: return ObjViewSettings_Flag(self) @@ -1584,8 +1613,6 @@ def typ_str(self) -> str: # EntryEnum ########################################################################################################### class EntryEnum(EntrySubconstruct): - construct: "cs.Enum" - def __init__( self, model: "model.ConstructEditorModel", @@ -1596,6 +1623,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.Enum": + return t.cast("cs.Enum", self._construct) + @property def typ_str(self) -> str: return super().typ_str + " as Enum" @@ -1651,8 +1682,6 @@ def conv_str_to_obj(self, s: str) -> Any: # EntryFlagsEnum ###################################################################################################### class EntryFlagsEnum(EntrySubconstruct): - construct: "cs.FlagsEnum" - def __init__( self, model: "model.ConstructEditorModel", @@ -1663,6 +1692,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cs.FlagsEnum": + return t.cast("cs.FlagsEnum", self._construct) + @property def typ_str(self) -> str: return super().typ_str + " as Flags" @@ -1715,8 +1748,6 @@ def get_enum_name(e: cst.EnumBase): class EntryTEnum(EntrySubconstruct): - construct: "cst.TEnum[Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -1727,6 +1758,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cst.TEnum[Any]": + return t.cast("cst.TEnum[Any]", self._construct) + @property def typ_str(self) -> str: return super().typ_str + " as Enum" @@ -1774,8 +1809,6 @@ def conv_str_to_obj(self, s: str) -> Any: # EntryTFlagsEnum ##################################################################################################### class EntryTFlagsEnum(EntrySubconstruct): - construct: "cst.TFlagsEnum[Any]" - def __init__( self, model: "model.ConstructEditorModel", @@ -1786,6 +1819,10 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) + @property + def construct(self) -> "cst.TFlagsEnum[Any]": + return t.cast("cst.TFlagsEnum[Any]", self._construct) + @property def typ_str(self) -> str: return super().typ_str + " as Flags" diff --git a/construct_editor/core/preprocessor.py b/construct_editor/core/preprocessor.py index 066677e..038c5d7 100644 --- a/construct_editor/core/preprocessor.py +++ b/construct_editor/core/preprocessor.py @@ -11,7 +11,7 @@ class GuiMetaData(t.TypedDict): byte_range: t.Tuple[int, int] - construct: cst.Construct + construct: cst.Construct[t.Any, t.Any] context: cst.Context stream: io.BytesIO child_gui_metadata: t.Optional["GuiMetaData"] @@ -41,7 +41,7 @@ class NoneWithGuiMetadata: pass -class ObjProxyWithGuiMetaData(wrapt.ObjectProxy): +class ObjProxyWithGuiMetaData(wrapt.ObjectProxy[t.Any]): __slots__ = "__construct_editor_metadata__" def __init__(self, wrapped: t.Any, gui_metadata: GuiMetaData): @@ -92,7 +92,7 @@ def add_gui_metadata(obj: t.Any, gui_metadata: GuiMetaData) -> t.Any: return obj -class IncludeGuiMetaData(cs.Subconstruct): +class IncludeGuiMetaData(cs.Subconstruct[t.Any, t.Any, t.Any, t.Any]): """Include GUI metadata to the parsed object""" def __init__(self, subcon, bitwise: bool): @@ -245,7 +245,7 @@ def include_metadata( for key, subcon in constr.cases.items(): new_cases[key] = include_metadata(subcon, bitwise) constr.cases = new_cases - if constr.default is not None: + if constr.default is not None: # type: ignore[reportUnnecessaryComparison] constr.default = include_metadata(constr.default, bitwise) return IncludeGuiMetaData(constr, bitwise) @@ -302,4 +302,4 @@ def include_metadata( raise ValueError(f"construct of type '{constr}' is not supported") -custom_subconstructs: t.List[t.Type[cs.Subconstruct]] = [] +custom_subconstructs: t.List[t.Type[cs.Subconstruct[t.Any, t.Any, t.Any, t.Any]]] = [] diff --git a/construct_editor/gallery/example_cmd_resp.py b/construct_editor/gallery/example_cmd_resp.py index e25d843..0404775 100644 --- a/construct_editor/gallery/example_cmd_resp.py +++ b/construct_editor/gallery/example_cmd_resp.py @@ -11,7 +11,7 @@ class DefaultSizedError(cs.ConstructError): pass -class DefaultSized(cs.Subconstruct): +class DefaultSized(cs.Subconstruct[t.Any, t.Any, t.Any, t.Any]): r""" Returns a size when calling sizeof of GreedyBytes. Parsing and building is not changed. diff --git a/construct_editor/gallery/example_ipstack.py b/construct_editor/gallery/example_ipstack.py index fa58b86..2489b9f 100644 --- a/construct_editor/gallery/example_ipstack.py +++ b/construct_editor/gallery/example_ipstack.py @@ -4,6 +4,8 @@ WARNING: before parsing the application layer over a TCP stream, you must first combine all the TCP frames into a stream. See utils.tcpip for some solutions. """ +import typing as t + from construct import * # type: ignore from construct.lib import * # type: ignore @@ -613,17 +615,22 @@ # Domain Name System (TCP/IP protocol stack) #=============================================================================== -class DnsStringAdapter(Adapter): + +class DnsStringAdapter(Adapter[t.Any, t.Any, t.Any, t.Any]): def _decode(self, obj, context, path): return u".".join(obj[:-1]) # type: ignore + def _encode(self, obj, context, path): return obj.split(u".") + [u""] # type: ignore -class DnsNamesAdapter(Adapter): + +class DnsNamesAdapter(Adapter[t.Any, t.Any, t.Any, t.Any]): def _decode(self, obj, context, path): return [x.label if x.islabel else x.pointer & 0x3fff for x in obj] # type: ignore + def _encode(self, obj, context, path): - return [dict(ispointer=1,pointer=x|0xc000) if isinstance(x,int) else dict(islabel=1,label=x) for x in obj] # type: ignore + return [dict(ispointer=1, pointer=x | 0xc000) if isinstance(x,int) else dict(islabel=1, label=x) for x in obj] # type: ignore + dns_record_class = Enum(Int16ub, RESERVED = 0, diff --git a/construct_editor/gallery/test_checksum.py b/construct_editor/gallery/test_checksum.py index 677273b..0facdd8 100644 --- a/construct_editor/gallery/test_checksum.py +++ b/construct_editor/gallery/test_checksum.py @@ -4,14 +4,20 @@ from . import GalleryItem + +def _hashfunc(data: bytes) -> bytes: + return hashlib.sha512(data).digest() + + constr = cs.Struct( "checksum_start" / cs.Tell, "fields" / cs.Struct( cs.Padding(1000), ), "checksum_end" / cs.Tell, - "checksum" / cs.Checksum(cs.Bytes(64), - lambda data: hashlib.sha512(data).digest(), + "checksum" / cs.Checksum( + cs.Bytes(64), + _hashfunc, lambda ctx: ctx._io.getvalue()[ctx.checksum_start:ctx.checksum_end]), # type: ignore ) diff --git a/construct_editor/main.py b/construct_editor/main.py index 31aa410..4e21450 100644 --- a/construct_editor/main.py +++ b/construct_editor/main.py @@ -181,6 +181,7 @@ def __init__(self, parent: ConstructGalleryFrame): self.gallery_selection = 1 default_gallery = list(self.construct_gallery.keys())[self.gallery_selection] default_gallery_item = self.construct_gallery[default_gallery] + assert default_gallery_item is not None # Define GUI elements ############################################# self.sizer = wx.BoxSizer(wx.HORIZONTAL) @@ -296,7 +297,7 @@ def on_gallery_selection_changed(self, event): ) example = self.example_selector_lbx.GetStringSelection() - example_binary = self.construct_gallery[selection].example_binarys[example] + example_binary = gallery_item.example_binarys[example] else: example_binary = bytes(0) @@ -315,11 +316,12 @@ def on_clear_binary_clicked(self, event): def on_example_selection_changed(self, event): selection = self.gallery_selector_lbx.GetStringSelection() example = self.example_selector_lbx.GetStringSelection() - example_binary = self.construct_gallery[selection].example_binarys[example] - - # Set example binary - self.construct_hex_editor.binary = example_binary - self.construct_hex_editor.construct_editor.expand_all() + gallery_item = self.construct_gallery[selection] + if gallery_item is not None: + # Set example binary + example_binary = gallery_item.example_binarys[example] + self.construct_hex_editor.binary = example_binary + self.construct_hex_editor.construct_editor.expand_all() def on_load_binary_file_clicked(self, event): with wx.FileDialog( @@ -403,7 +405,7 @@ def main(): ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) inspect = False - if inspect is True: + if inspect is True: # type: ignore[reportUnnecessaryComparison] import wx.lib.mixins.inspection as wit app = wit.InspectableApp() diff --git a/construct_editor/wx_widgets/wx_construct_editor.py b/construct_editor/wx_widgets/wx_construct_editor.py index a8f0bcd..ac45aa6 100644 --- a/construct_editor/wx_widgets/wx_construct_editor.py +++ b/construct_editor/wx_widgets/wx_construct_editor.py @@ -6,6 +6,7 @@ import construct as cs import wx import wx.dataview as dv +from wx.dataview import DataViewItem from construct_editor.core.construct_editor import ConstructEditor from construct_editor.core.entries import EntryConstruct @@ -53,10 +54,10 @@ def GetSize(self): raise ValueError("`entry_renderer_helper` not set") return self.entry_renderer_helper.get_size(self) - def Render(self, rect: wx.Rect, dc: wx.DC, state): + def Render(self, cell: wx.Rect, dc: wx.DC, state: int) -> bool: if self.entry_renderer_helper is None: raise ValueError("`entry_renderer_helper` not set") - return self.entry_renderer_helper.render(self, rect, dc, state) + return self.entry_renderer_helper.render(self, cell, dc, state) def GetMode(self) -> int: """ @@ -101,16 +102,16 @@ def GetMode(self) -> int: def ActivateCell( self, - rect: wx.Rect, + cell: wx.Rect, model: dv.DataViewModel, item: dv.DataViewItem, col: int, - mouseEvent: wx.MouseEvent | None, - ): + mouseEvent: wx.MouseEvent, + ) -> bool: if self.entry_renderer_helper is None: raise ValueError("`entry_renderer_helper` not set") return self.entry_renderer_helper.activate_cell( - self, rect, model, item, col, mouseEvent + self, cell, model, item, col, mouseEvent ) # The HasEditorCtrl, CreateEditorCtrl and GetValueFromEditorCtrl @@ -130,7 +131,8 @@ def CreateEditorCtrl( editor.SetSize(labelRect.GetSize()) return editor - def GetValueFromEditorCtrl(self, editor: WxObjEditor): + def GetValueFromEditorCtrl(self, editor: wx.Window) -> ValueFromEditorCtrl: + editor = t.cast("WxObjEditor", editor) new_obj = editor.get_new_obj() return ValueFromEditorCtrl(new_obj) @@ -191,7 +193,7 @@ def on_value_changed(self, entry: "EntryConstruct"): # ################################################################################################################# # dv.PyDataViewModel Interface #################################################################################### # ################################################################################################################# - def GetChildren(self, parent, children): + def GetChildren(self, item: dv.DataViewItem, children: t.List[dv.DataViewItem]) -> int: # The view calls this method to find the children of any node in the # control. There is an implicit hidden root node, and the top level # item(s) should be reported as children of this node. A List view @@ -206,11 +208,11 @@ def GetChildren(self, parent, children): if self.root_entry is None: return 0 - if not parent: + if not item: # hidden root entry = None else: - entry = self.dvc_item_to_entry(parent) + entry = self.dvc_item_to_entry(item) childs = self.get_children(entry) for child in childs: @@ -256,12 +258,12 @@ def GetValue(self, item: dv.DataViewItem, col: int): return self.get_value(entry, col) - def SetValue(self, value: ValueFromEditorCtrl, item: dv.DataViewItem, col: int): - if not isinstance(value, ValueFromEditorCtrl): - raise ValueError(f"value has the wrong type ({value})") + def SetValue(self, variant: ValueFromEditorCtrl, item: DataViewItem, col: int) -> bool: + if not isinstance(variant, ValueFromEditorCtrl): + raise ValueError(f"value has the wrong type ({variant})") entry = self.dvc_item_to_entry(item) - self.set_value(value.new_obj, entry, col) + self.set_value(variant.new_obj, entry, col) return True @@ -269,7 +271,7 @@ def GetAttr(self, item, col, attr): entry = self.dvc_item_to_entry(item) if entry is self.root_entry: - attr.SetColour("blue") + attr.SetColour(wx.BLUE) attr.SetBold(True) return True @@ -280,7 +282,7 @@ class WxConstructEditor(wx.Panel, ConstructEditor): def __init__( self, parent, - construct: cs.Construct, + construct: cs.Construct[t.Any, t.Any], ): wx.Panel.__init__(self, parent) self._init_gui() @@ -664,7 +666,7 @@ def _put_to_clipboard(self, txt: str): wx.TheClipboard.SetData(wx.TextDataObject(txt)) wx.TheClipboard.Close() - def _get_from_clipboard(self): + def _get_from_clipboard(self) -> str | None: """ Get text from the clipboard. """ diff --git a/construct_editor/wx_widgets/wx_construct_hex_editor.py b/construct_editor/wx_widgets/wx_construct_hex_editor.py index 12f7f87..89ee390 100644 --- a/construct_editor/wx_widgets/wx_construct_hex_editor.py +++ b/construct_editor/wx_widgets/wx_construct_hex_editor.py @@ -62,11 +62,10 @@ def clear_sub_panels(self): def create_sub_panel(self, name: str, bitwise: bool) -> "HexEditorPanel": """Create a new sub-panel""" if self.sub_panel is None: - self.sub_panel = HexEditorPanel( - self, name, read_only=True, bitwiese=bitwise - ) - self.SplitHorizontally(self.GetWindow1(), self.sub_panel) - return self.sub_panel + new_panel = HexEditorPanel(self, name, read_only=True, bitwiese=bitwise) + self.sub_panel = new_panel + self.SplitHorizontally(self.GetWindow1(), new_panel) + return new_panel else: raise RuntimeError("sub-panel already created") @@ -75,13 +74,13 @@ class WxConstructHexEditor(wx.Panel): def __init__( self, parent, - construct: cs.Construct, - contextkw: dict = {}, + construct: cs.Construct[t.Any, t.Any], + contextkw: dict[t.Any, t.Any] | None = None, binary: bytes = b"", ): super().__init__(parent) - self._contextkw = contextkw + self._contextkw = contextkw or {} hsizer = wx.BoxSizer(wx.HORIZONTAL) self._init_gui_hex_editor_splitter(hsizer, binary) @@ -113,11 +112,9 @@ def _init_gui_hex_visibility(self, hsizer: wx.BoxSizer): self, wx.ID_ANY, "«", size=wx.Size(12, -1) ) hsizer.Add(self.toggle_hex_visibility_btn, 0, wx.EXPAND | wx.ALL, 0) - self.toggle_hex_visibility_btn.Bind( - wx.EVT_BUTTON, lambda evt: self.toggle_hex_visibility() - ) + self.toggle_hex_visibility_btn.Bind(wx.EVT_BUTTON, self.toggle_hex_visibility) - def _init_gui_construct_editor(self, hsizer: wx.BoxSizer, construct: cs.Construct): + def _init_gui_construct_editor(self, hsizer: wx.BoxSizer, construct: cs.Construct[t.Any, t.Any]): self.construct_editor: WxConstructEditor = WxConstructEditor( self, construct, @@ -150,13 +147,13 @@ def toggle_hex_visibility(self): self.Refresh() self.Thaw() - def change_construct(self, constr: cs.Construct) -> None: + def change_construct(self, constr: cs.Construct[t.Any, t.Any]) -> None: """ Change the construct format, that is used for building/parsing. """ self.construct_editor.change_construct(constr) - def change_contextkw(self, contextkw: dict): + def change_contextkw(self, contextkw: dict[t.Any, t.Any]) -> None: """ Change the contextkw used for building/parsing. """ @@ -170,25 +167,25 @@ def change_binary(self, binary: bytes): self.hex_panel.hex_editor.binary = binary @property - def construct(self) -> cs.Construct: + def construct(self) -> cs.Construct[t.Any, t.Any]: """ Construct that is used for displaying. """ return self.construct_editor.construct @construct.setter - def construct(self, constr: cs.Construct): + def construct(self, constr: cs.Construct[t.Any, t.Any]): self.construct_editor.construct = constr @property - def contextkw(self) -> dict: + def contextkw(self) -> dict[t.Any, t.Any]: """ Context used for building/parsing. """ return self._contextkw @contextkw.setter - def contextkw(self, contextkw: dict): + def contextkw(self, contextkw: dict[t.Any, t.Any]): self.change_contextkw(contextkw) @property diff --git a/construct_editor/wx_widgets/wx_hex_editor.py b/construct_editor/wx_widgets/wx_hex_editor.py index 0de7776..fa1e787 100644 --- a/construct_editor/wx_widgets/wx_hex_editor.py +++ b/construct_editor/wx_widgets/wx_hex_editor.py @@ -7,6 +7,7 @@ import wx import wx.grid as Grid +from wx.grid import GridCellAttr from construct_editor.core.callbacks import CallbackList @@ -62,15 +63,16 @@ def __init__(self): True, f"Overwrite Range (Index: {idx}, Length: {len(byts)})" ) - def Do(self): + def Do(self) -> bool: self._range_backup = obj._binary[idx : idx + len(byts)] - if obj._binary[idx : idx + len(byts)] == byts: + byts_array = bytearray(byts) + if obj._binary[idx : idx + len(byts)] == byts_array: return False - obj._binary[idx : idx + len(byts)] = byts + obj._binary[idx : idx + len(byts)] = byts_array obj.on_binary_changed.fire(obj) return True - def Undo(self): + def Undo(self) -> bool: obj._binary[idx : idx + len(byts)] = self._range_backup obj.on_binary_changed.fire(obj) return True @@ -474,7 +476,7 @@ def SetSize(self, rect): rect.x - 4, rect.y, rect.width + 8, rect.height + 2, wx.SIZE_ALLOW_MINUS_ONE ) - def Show(self, show, attr): + def Show(self, show: bool, attr: GridCellAttr | None = None) -> None: """ Show or hide the edit control. You can use the attr (if not None) to set colours or fonts for the control. @@ -548,32 +550,32 @@ def Reset(self): self._tc.SetValue(self.startValue) self._tc.SetInsertionPointEnd() - def IsAcceptedKey(self, evt): + def IsAcceptedKey(self, event: wx.KeyEvent) -> bool: """ Return True to allow the given key to start editing: the base class version only checks that the event has no modifiers. F2 is special and will always start the editor. """ - logger.debug("keycode=%d" % (evt.GetKeyCode())) + logger.debug("keycode=%d" % (event.GetKeyCode())) # We can ask the base class to do it # return self.base_IsAcceptedKey(evt) # or do it ourselves return ( - not (evt.ControlDown() or evt.AltDown()) - and evt.GetKeyCode() != wx.WXK_SHIFT + not (event.ControlDown() or event.AltDown()) + and event.GetKeyCode() != wx.WXK_SHIFT ) - def StartingKey(self, evt): + def StartingKey(self, event: wx.KeyEvent) -> None: """ If the editor is enabled by pressing keys on the grid, this will be called to let the editor do something about that first key if desired. """ - logger.debug("keycode=%d" % evt.GetKeyCode()) - key = evt.GetKeyCode() + logger.debug("keycode=%d" % event.GetKeyCode()) + key = event.GetKeyCode() if not self._tc.insert_first_key(key): - evt.Skip() + event.Skip() def StartingClick(self): """ diff --git a/construct_editor/wx_widgets/wx_obj_view.py b/construct_editor/wx_widgets/wx_obj_view.py index 1114b0a..9f47a2e 100644 --- a/construct_editor/wx_widgets/wx_obj_view.py +++ b/construct_editor/wx_widgets/wx_obj_view.py @@ -391,7 +391,7 @@ def render( renderer.RenderText(obj_str, 0, rect, dc, state) return True - def get_mode(self): + def get_mode(self) -> int: return dv.DATAVIEW_CELL_EDITABLE def activate_cell( @@ -402,7 +402,7 @@ def activate_cell( item: dv.DataViewItem, col: int, mouse_event: wx.MouseEvent | None, - ): + ) -> bool: return False @@ -436,7 +436,7 @@ def render( native_renderer.DrawCheckBox(win, dc, rect, flags) return True - def get_mode(self): + def get_mode(self) -> int: return dv.DATAVIEW_CELL_ACTIVATABLE def activate_cell( @@ -447,7 +447,7 @@ def activate_cell( item: dv.DataViewItem, col: int, mouse_event: wx.MouseEvent | None, - ): + ) -> bool: # see wxWidgets: wxDataViewToggleRenderer::WXActivateCell if mouse_event is not None: diff --git a/construct_editor/wx_widgets/wx_python_code_editor.py b/construct_editor/wx_widgets/wx_python_code_editor.py index 5a8f3e4..8ad3081 100644 --- a/construct_editor/wx_widgets/wx_python_code_editor.py +++ b/construct_editor/wx_widgets/wx_python_code_editor.py @@ -218,7 +218,7 @@ def OnMarginClick(self, evt): # fold and unfold as needed if evt.GetMargin() == 2: if evt.GetShift() and evt.GetControl(): - self.FoldAll() + self.FoldAll(1) else: lineClicked = self.LineFromPosition(evt.GetPosition()) @@ -236,7 +236,7 @@ def OnMarginClick(self, evt): else: self.ToggleFold(lineClicked) - def FoldAll(self): + def FoldAll(self, action: int): lineCount = self.GetLineCount() expanding = True @@ -349,8 +349,8 @@ def SetValue(self, value): self.SetSavePoint() self.SetReadOnly(val) - def SetEditable(self, val): - self.SetReadOnly(not val) + def SetEditable(self, editable: bool) -> None: + self.SetReadOnly(not editable) def IsModified(self): return self.GetModify() @@ -373,15 +373,15 @@ def GetLastPosition(self): def GetPositionFromLine(self, line): return self.PositionFromLine(line) - def GetRange(self, start, end): - return self.GetTextRange(start, end) + def GetRange(self, from_: int, to_: int) -> str: + return self.GetTextRange(from_, to_) def GetSelection(self): return self.GetAnchor(), self.GetCurrentPos() - def SetSelection(self, start, end): - self.SetSelectionStart(start) - self.SetSelectionEnd(end) + def SetSelection(self, from_: int, to_: int): + self.SetSelectionStart(from_) + self.SetSelectionEnd(to_) def SelectLine(self, line): start = self.PositionFromLine(line) diff --git a/pyproject.toml b/pyproject.toml index 181a23a..4fb6986 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,21 +124,14 @@ exclude = [ # These warnings should be activated as "error" in the future, but for now we don't want to refactor the entire codebase right now. # Valid values: "error", "warning", "information", "none" -reportArgumentType = "none" -reportAttributeAccessIssue = "none" -reportIncompatibleMethodOverride = "none" -reportInvalidTypeArguments = "none" -reportMissingParameterType = "none" -reportMissingTypeArgument = "none" -reportMissingTypeStubs = "none" -reportOptionalMemberAccess = "none" -reportUnknownArgumentType = "none" -reportUnknownLambdaType = "none" -reportUnknownMemberType = "none" -reportUnknownParameterType = "none" -reportUnknownVariableType = "none" -reportUnnecessaryComparison = "none" -reportUnusedVariable = "none" +reportArgumentType = "none" # 6 errors +reportAttributeAccessIssue = "none" # 8 errors +reportMissingParameterType = "none" # 130 errors +reportMissingTypeStubs = "none" # 11 errors +reportUnknownArgumentType = "none" # 132 errors +reportUnknownMemberType = "none" # 242 errors +reportUnknownParameterType = "none" # 64 errors +reportUnknownVariableType = "none" # 61 errors # These "unnecessary isinstance" checks often enhance readability or increase the future-proofness of the code, # since you can then explicitly "raise" for other types. So we don't want to complain about them. reportUnnecessaryIsInstance = "none" From 1178e0b13b57432b7f2d46ef0db3a997b32260fb Mon Sep 17 00:00:00 2001 From: "Robin.Schmidt" Date: Tue, 21 Jul 2026 18:06:01 +0200 Subject: [PATCH 6/7] MyPy fixes --- construct_editor/core/entries.py | 18 ++++---- .../gallery/test_switch_dataclass.py | 45 ++++++++++--------- construct_editor/wx_widgets/wx_hex_editor.py | 5 ++- construct_editor/wx_widgets/wx_obj_view.py | 12 ++--- pyproject.toml | 6 --- 5 files changed, 40 insertions(+), 46 deletions(-) diff --git a/construct_editor/core/entries.py b/construct_editor/core/entries.py index 6cd5c49..cc9b985 100644 --- a/construct_editor/core/entries.py +++ b/construct_editor/core/entries.py @@ -526,7 +526,7 @@ def __init__( ): super().__init__(model, parent, construct, name, docs) - self._subentries = [] + self._subentries: list[EntryConstruct] = [] @property def construct(self) -> "cs.Array[Any, Any] | cs.GreedyRange[Any, Any]": @@ -1672,12 +1672,11 @@ def conv_str_to_obj(self, s: str) -> Any: value = str_to_int(s) if value in self.construct.decmapping: - new_obj = self.construct.decmapping[value] + return self.construct.decmapping[value] else: - new_obj = cs.EnumInteger(value) + return cs.EnumInteger(value) except Exception: - new_obj = s # this will probably result in a binary-build-error - return new_obj + return s # this will probably result in a binary-build-error # EntryFlagsEnum ###################################################################################################### @@ -1733,7 +1732,7 @@ def get_flagsenum_items_from_obj(self) -> t.List[FlagsEnumItem]: def conv_flagsenum_items_to_obj(self, items: t.List[FlagsEnumItem]) -> Any: """Convert flagsenum items to object""" - new_obj = cs.Container() + new_obj: cs.Container[t.Any] = cs.Container[t.Any]() for item in items: if item.checked: new_obj[item.name] = True @@ -1798,13 +1797,12 @@ def conv_str_to_obj(self, s: str) -> Any: enum_type: t.Type[cst.EnumBase] = self.construct.enum_type try: try: - new_obj = enum_type[s] + return enum_type[s] except KeyError: value = str_to_int(s) - new_obj = enum_type(value) + return enum_type(value) except Exception: - new_obj = s # this will probably result in a binary-build-error - return new_obj + return s # this will probably result in a binary-build-error # EntryTFlagsEnum ##################################################################################################### diff --git a/construct_editor/gallery/test_switch_dataclass.py b/construct_editor/gallery/test_switch_dataclass.py index 64ec04d..13f601b 100644 --- a/construct_editor/gallery/test_switch_dataclass.py +++ b/construct_editor/gallery/test_switch_dataclass.py @@ -1,4 +1,5 @@ import dataclasses +import typing as t import construct as cs import construct_typed as cst @@ -42,28 +43,32 @@ def get_default(cls): return cls(0) choice: int = cst.csfield(cst.TEnum(cs.Int8ub, Choice)) - switch: Case1 | Case2 | CaseDefault | None = cst.csfield_noinit( - cs.Switch( - cs.this.choice, - cases={ - 1: cs.Default(cst.DataclassStruct(Case1), Case1.get_default()), - 2: cs.Default(cst.DataclassStruct(Case2), Case2.get_default()), - }, - default=cs.Default( - cst.DataclassStruct(CaseDefault), CaseDefault.get_default() - ), - ) + switch: Case1 | Case2 | CaseDefault | None = t.cast( + "Case1 | Case2 | CaseDefault | None", + cst.csfield_noinit( + cs.Switch( + cs.this.choice, + cases={ + 1: cs.Default(cst.DataclassStruct(Case1), Case1.get_default()), + 2: cs.Default(cst.DataclassStruct(Case2), Case2.get_default()), + }, + default=cs.Default(cst.DataclassStruct(CaseDefault), CaseDefault.get_default()), + ) + ), ) - switch_without_default: Case1 | Case2 | None = cst.csfield_noinit( - cs.Switch( - cs.this.choice, - cases={ - 1: cs.Default(cst.DataclassStruct(Case1), Case1.get_default()), - 2: cs.Default(cst.DataclassStruct(Case2), Case2.get_default()), - }, - default=cs.Default(cs.Pass, None), - ) + switch_without_default: Case1 | Case2 | None = t.cast( + "Case1 | Case2 | None", + cst.csfield_noinit( + cs.Switch( + cs.this.choice, + cases={ + 1: cs.Default(cst.DataclassStruct(Case1), Case1.get_default()), + 2: cs.Default(cst.DataclassStruct(Case2), Case2.get_default()), + }, + default=cs.Default(cs.Pass, None), + ) + ), ) diff --git a/construct_editor/wx_widgets/wx_hex_editor.py b/construct_editor/wx_widgets/wx_hex_editor.py index fa1e787..873336e 100644 --- a/construct_editor/wx_widgets/wx_hex_editor.py +++ b/construct_editor/wx_widgets/wx_hex_editor.py @@ -1124,11 +1124,12 @@ def _on_cell_right_click(self, event: Grid.GridEvent): if menu is None: popup_menu.AppendSeparator() continue + item: wx.MenuItem if menu.toggle_state is not None: # checkbox boolean state - item: wx.MenuItem = popup_menu.AppendCheckItem(menu.wx_id, menu.name) + item = popup_menu.AppendCheckItem(menu.wx_id, menu.name) item.Check(menu.toggle_state) else: - item: wx.MenuItem = popup_menu.Append(menu.wx_id, menu.name) + item = popup_menu.Append(menu.wx_id, menu.name) self.Bind(wx.EVT_MENU, menu.callback, id=item.Id) item.Enable(menu.enabled) diff --git a/construct_editor/wx_widgets/wx_obj_view.py b/construct_editor/wx_widgets/wx_obj_view.py index 9f47a2e..d8a283d 100644 --- a/construct_editor/wx_widgets/wx_obj_view.py +++ b/construct_editor/wx_widgets/wx_obj_view.py @@ -80,11 +80,9 @@ def get_new_obj(self) -> t.Any: try: # convert string to integer - new_obj = str_to_int(val_str) + return str_to_int(val_str) except Exception: - new_obj = val_str # this will probably result in a building error - - return new_obj + return val_str # this will probably result in a building error class WxObjEditor_Bytes(wx.TextCtrl): @@ -105,11 +103,9 @@ def get_new_obj(self) -> t.Any: try: # convert string to bytes - new_obj = str_to_bytes(val_str) + return str_to_bytes(val_str) except Exception: - new_obj = val_str # this will probably result in a building error - - return new_obj + return val_str # this will probably result in a building error class WxObjEditor_Enum(wx.ComboBox): diff --git a/pyproject.toml b/pyproject.toml index 4fb6986..022df9b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,20 +92,14 @@ strict = true # These errors should be activated in the future, but for now we don't want to refactor the entire codebase right now. disable_error_code = [ "arg-type", - "assignment", "attr-defined", "import-untyped", "misc", "no-any-return", "no-untyped-call", "no-untyped-def", - "no-redef", - "return-value", "str-bytes-safe", - "type-arg", - "union-attr", "unused-ignore", - "var-annotated", ] [tool.pyright] From f7963da6e4fdc93b0c08a67e94e325316343e1db Mon Sep 17 00:00:00 2001 From: "Robin.Schmidt" Date: Tue, 21 Jul 2026 18:24:51 +0200 Subject: [PATCH 7/7] Reverted false `type-arg` fixes. --- construct_editor/core/preprocessor.py | 4 ++-- construct_editor/gallery/example_cmd_resp.py | 4 ++-- construct_editor/gallery/example_ipstack.py | 5 ++--- construct_editor/gallery/test_computed.py | 20 ++++++++++---------- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/construct_editor/core/preprocessor.py b/construct_editor/core/preprocessor.py index 038c5d7..d513e68 100644 --- a/construct_editor/core/preprocessor.py +++ b/construct_editor/core/preprocessor.py @@ -92,7 +92,7 @@ def add_gui_metadata(obj: t.Any, gui_metadata: GuiMetaData) -> t.Any: return obj -class IncludeGuiMetaData(cs.Subconstruct[t.Any, t.Any, t.Any, t.Any]): +class IncludeGuiMetaData(cs.Subconstruct): # type: ignore[type-arg] """Include GUI metadata to the parsed object""" def __init__(self, subcon, bitwise: bool): @@ -302,4 +302,4 @@ def include_metadata( raise ValueError(f"construct of type '{constr}' is not supported") -custom_subconstructs: t.List[t.Type[cs.Subconstruct[t.Any, t.Any, t.Any, t.Any]]] = [] +custom_subconstructs: t.List[t.Type[cs.Subconstruct]] = [] # type: ignore[type-arg] diff --git a/construct_editor/gallery/example_cmd_resp.py b/construct_editor/gallery/example_cmd_resp.py index 0404775..042a0d6 100644 --- a/construct_editor/gallery/example_cmd_resp.py +++ b/construct_editor/gallery/example_cmd_resp.py @@ -11,14 +11,14 @@ class DefaultSizedError(cs.ConstructError): pass -class DefaultSized(cs.Subconstruct[t.Any, t.Any, t.Any, t.Any]): +class DefaultSized(cs.Subconstruct): # type: ignore[type-arg] r""" Returns a size when calling sizeof of GreedyBytes. Parsing and building is not changed. :param subcon: Construct instance :param default_size: size that should be returned - :raises DefaultSizedError: anouter GreedyBytes than GreedyBytes is passed + :raises DefaultSizedError: another GreedyBytes than GreedyBytes is passed Example:: diff --git a/construct_editor/gallery/example_ipstack.py b/construct_editor/gallery/example_ipstack.py index 2489b9f..4cc5dc8 100644 --- a/construct_editor/gallery/example_ipstack.py +++ b/construct_editor/gallery/example_ipstack.py @@ -4,7 +4,6 @@ WARNING: before parsing the application layer over a TCP stream, you must first combine all the TCP frames into a stream. See utils.tcpip for some solutions. """ -import typing as t from construct import * # type: ignore from construct.lib import * # type: ignore @@ -616,7 +615,7 @@ #=============================================================================== -class DnsStringAdapter(Adapter[t.Any, t.Any, t.Any, t.Any]): +class DnsStringAdapter(Adapter): # type: ignore[type-arg] def _decode(self, obj, context, path): return u".".join(obj[:-1]) # type: ignore @@ -624,7 +623,7 @@ def _encode(self, obj, context, path): return obj.split(u".") + [u""] # type: ignore -class DnsNamesAdapter(Adapter[t.Any, t.Any, t.Any, t.Any]): +class DnsNamesAdapter(Adapter): # type: ignore[type-arg] def _decode(self, obj, context, path): return [x.label if x.islabel else x.pointer & 0x3fff for x in obj] # type: ignore diff --git a/construct_editor/gallery/test_computed.py b/construct_editor/gallery/test_computed.py index 8d93965..4bf3f3a 100644 --- a/construct_editor/gallery/test_computed.py +++ b/construct_editor/gallery/test_computed.py @@ -8,16 +8,16 @@ @dataclasses.dataclass class ComputedTest(cst.DataclassMixin): - type_int_const: int = cst.csfield(cs.Computed(50)) - type_int_lambda: int = cst.csfield(cs.Computed(lambda ctx: 50)) - type_float_const: float = cst.csfield(cs.Computed(80.0)) - type_float_lambda: float = cst.csfield(cs.Computed(lambda ctx: 80.0)) - type_bool_const: bool = cst.csfield(cs.Computed(True)) - type_bool_lambda: bool = cst.csfield(cs.Computed(lambda ctx: True)) - type_bytes_const: bytes = cst.csfield(cs.Computed(bytes([0x00, 0xAB]))) - type_bytes_lambda: bytes = cst.csfield(cs.Computed(lambda ctx: bytes([0x00, 0xAB]))) - type_bytearray_const: bytearray = cst.csfield(cs.Computed(bytearray([0x00, 0xAB, 0xFF]))) - type_bytearray_lambda: bytearray = cst.csfield(cs.Computed(lambda ctx: bytearray([0x00, 0xAB, 0xFF]))) + type_int_const: int | None = cst.csfield_noinit(cs.Computed(50)) + type_int_lambda: int | None = cst.csfield_noinit(cs.Computed(lambda ctx: 50)) + type_float_const: float | None = cst.csfield_noinit(cs.Computed(80.0)) + type_float_lambda: float | None = cst.csfield_noinit(cs.Computed(lambda ctx: 80.0)) + type_bool_const: bool | None = cst.csfield_noinit(cs.Computed(True)) + type_bool_lambda: bool | None = cst.csfield_noinit(cs.Computed(lambda ctx: True)) + type_bytes_const: bytes | None = cst.csfield_noinit(cs.Computed(bytes([0x00, 0xAB]))) + type_bytes_lambda: bytes | None = cst.csfield_noinit(cs.Computed(lambda ctx: bytes([0x00, 0xAB]))) + type_bytearray_const: bytearray | None = cst.csfield_noinit(cs.Computed(bytearray([0x00, 0xAB, 0xFF]))) + type_bytearray_lambda: bytearray | None = cst.csfield_noinit(cs.Computed(lambda ctx: bytearray([0x00, 0xAB, 0xFF]))) constr = cst.DataclassStruct(ComputedTest)