Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,47 @@ The preferred way to installation is via PyPI:
pip install construct-editor
```

## Tests
Unittests are in development and will be added by PR #40.

The following static type checkers are fully supported:
- [mypy](https://github.com/python/mypy)
- [pyright](https://github.com/microsoft/pyright)
- [ty](https://github.com/astral-sh/ty) (experimental, since ty itself is still in development)

## Development

This project uses `uv` as a project management tool. To set up your development environment, run the following command:

```bash
uv sync
```

To run the unit tests, run:

```bash
uv run poe test
```
Note: Unittests are in development and will be added by PR #40. For now, this command is a placeholder and does nothing.

To run the linter/code formatter (including auto fix), run:

```bash
uv run poe lint
```

To run all supported type checkers, run:

```bash
uv run poe typecheck
```

To run unit tests, linter/code formatter and type checkers, run:

```bash
uv run poe check-all
```

## Getting started (Standalone)
To start the standalone version, just execute the following in the command line:
```
Expand Down
2 changes: 1 addition & 1 deletion construct_editor/core/construct_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def show_status(self, path_info: str, bytes_info: str):
"""

@abc.abstractmethod
def get_selected_entry(self) -> "entries.EntryConstruct":
def get_selected_entry(self) -> "entries.EntryConstruct | None":
"""
Get the currently selected entry (or None if nothing is selected).

Expand Down
6 changes: 4 additions & 2 deletions construct_editor/core/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ def __init__(
self.old_value = old_value
self.new_value = new_value

def do(self) -> None:
def do(self) -> bool:
self.entry.obj = self.new_value
self.entry.model.on_value_changed(self.entry)
return True

def undo(self) -> None:
def undo(self) -> bool:
self.entry.obj = self.old_value
self.entry.model.on_value_changed(self.entry)
return True


class ConstructEditorModel:
Expand Down
10 changes: 5 additions & 5 deletions construct_editor/wx_widgets/wx_construct_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ def GetMode(self) -> int:
(see `HasEditorCtrl`, `CreateEditorCtrl`, `GetValueFromEditorCtrl`)

"""
# `SetValue` is not called befor `GetMode` is called, so
# `SetValue` is not called before `GetMode` is called, so
# `self.entry_renderer_helper` is not valid to use here. So we
# have to detect the selecte item of the dvc and assume that
# have to detect the selected item of the dvc and assume that
# we need to get the mode for this item. (Fingers crossed that
# this always works.)

dvc: "dv.DataViewCtrl" = self.GetView()
editor: "WxConstructEditor" = dvc.GetParent()
editor = t.cast("WxConstructEditor", dvc.GetParent())
selected_entry = editor.get_selected_entry()
if selected_entry is None:
mode = dv.DATAVIEW_CELL_INERT
Expand Down Expand Up @@ -126,8 +126,8 @@ def CreateEditorCtrl(
) -> WxObjEditor:
view_settings = value.obj_view_settings
editor: WxObjEditor = create_obj_editor(parent, view_settings)
editor.SetPosition(labelRect.Position)
editor.SetSize(labelRect.Size)
editor.SetPosition(labelRect.GetPosition())
editor.SetSize(labelRect.GetSize())
return editor

def GetValueFromEditorCtrl(self, editor: WxObjEditor):
Expand Down
8 changes: 4 additions & 4 deletions construct_editor/wx_widgets/wx_hex_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def __init__(self, editor: "WxHexEditor", binary_data: HexEditorBinaryData):

self._attr_default = Grid.GridCellAttr()
self._attr_default.SetFont(self.font)
self._attr_default.SetBackgroundColour("white")
self._attr_default.SetBackgroundColour(wx.WHITE)

self._attr_selected = Grid.GridCellAttr()
self._attr_selected.SetFont(self.font)
Expand Down Expand Up @@ -381,7 +381,7 @@ def on_key_down(self, evt):
key = evt.GetKeyCode()

if key == wx.WXK_BACK or key == wx.WXK_DELETE:
self.SetValue(self.startValue)
self.SetValue(self.startValue or "")
self.Clear()

if key == wx.WXK_TAB:
Expand All @@ -394,7 +394,7 @@ def on_key_down(self, evt):
or key == wx.WXK_LEFT
or key == wx.WXK_RIGHT
):
self.SetValue(self.startValue)
self.SetValue(self.startValue or "")
wx.CallAfter(self.parentgrid._abort_edit)
return
elif self.mode == "hex":
Expand Down Expand Up @@ -1315,7 +1315,7 @@ class MyFrame(wx.Frame):
"""We simply derive a new class of Frame."""

def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(420, 800))
wx.Frame.__init__(self, parent, title=title, size=wx.Size(420, 800))

# Create an instance of our model...
self.hex_editor = WxHexEditor(self)
Expand Down
10 changes: 5 additions & 5 deletions construct_editor/wx_widgets/wx_obj_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
# Value Editors
# #####################################################################################################################
class WxObjEditor_Default(wx.TextCtrl):
def __init__(self, parent, settings: ObjViewSettings):
def __init__(self, parent: wx.Window, settings: ObjViewSettings):
self.entry = settings.entry

super(wx.TextCtrl, self).__init__(
super().__init__(
parent,
wx.ID_ANY,
self.entry.obj_str,
Expand All @@ -48,7 +48,7 @@ class WxObjEditor_String(wx.TextCtrl):
def __init__(self, parent, settings: ObjViewSettings_String):
self.entry = settings.entry

super(wx.TextCtrl, self).__init__(
super().__init__(
parent,
wx.ID_ANY,
self.entry.obj_str,
Expand All @@ -66,7 +66,7 @@ class WxObjEditor_Integer(wx.TextCtrl):
def __init__(self, parent, settings: ObjViewSettings_Integer):
self.entry = settings.entry

super(wx.TextCtrl, self).__init__(
super().__init__(
parent,
wx.ID_ANY,
self.entry.obj_str,
Expand All @@ -91,7 +91,7 @@ class WxObjEditor_Bytes(wx.TextCtrl):
def __init__(self, parent, settings: ObjViewSettings_Bytes):
self.entry = settings.entry

super(wx.TextCtrl, self).__init__(
super().__init__(
parent,
wx.ID_ANY,
settings.entry.obj_str,
Expand Down
2 changes: 1 addition & 1 deletion construct_editor/wx_widgets/wx_python_code_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ def SetUpEditor(self):
# Caret color
self.SetCaretForeground("BLUE")
# Selection background
self.SetSelBackground(1, "#66CCFF")
self.SetSelBackground(True, "#66CCFF")

# Attempt to set caret blink rate.
try:
Expand Down
73 changes: 64 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ version = "0.2.0"
description = "GUI (based on wxPython) for 'construct', which is a powerful declarative and symmetrical parser and builder for binary data."
readme = "README.md"
license = "MIT"
license-files = ["LICENSE"]
authors = [{ name = "Tim Riddermann" }]
requires-python = ">=3.10"
keywords = [
Expand Down Expand Up @@ -63,10 +64,11 @@ construct-editor = "construct_editor.main:main"

[dependency-groups]
dev = [
"poethepoet>=0.46.0",
"pyright>=1.1.410",
"ruff>=0.15.16",
"ty>=0.0.46",
"poethepoet>=0.48.0",
"mypy>=2.3.0",
"pyright>=1.1.411",
"ruff>=0.15.21",
"ty>=0.0.59",
"cryptography", # optional "extra" from construct that the user may or may not have installed
"cloudpickle", # optional "extra" from construct that the user may or may not have installed
"lz4", # optional "extra" from construct that the user may or may not have installed
Expand All @@ -85,6 +87,27 @@ include = [
[tool.setuptools.package-data]
construct_editor = ["py.typed"]

[tool.mypy]
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]
typeCheckingMode = "strict"
exclude = [
Expand All @@ -103,7 +126,6 @@ exclude = [
# Valid values: "error", "warning", "information", "none"
reportArgumentType = "none"
reportAttributeAccessIssue = "none"
reportGeneralTypeIssues = "none"
reportIncompatibleMethodOverride = "none"
reportInvalidTypeArguments = "none"
reportMissingParameterType = "none"
Expand Down Expand Up @@ -137,6 +159,7 @@ 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", "warn", "ignore"
[tool.ty.rules]
invalid-argument-type = "ignore"
invalid-assignment = "ignore"
invalid-method-override = "ignore"
invalid-type-arguments = "ignore"
Expand Down Expand Up @@ -167,10 +190,42 @@ ignore = [
"F841", # Local variable `...` is assigned to but never used
]

[tool.poe.tasks.test]
# Tests are not yet implemented and will be added with PR #40.
# cmd = "pytest $POE_EXTRA_ARGS"
sequence = []
executor = {type = "uv", isolated = true}

[tool.poe.tasks.lint]
cmd = "ruff check --fix --show-fixes"
executor = { type = "uv", isolated = true }

[tool.poe.tasks.lint-checkonly]
cmd = "ruff check"
executor = { type = "uv", isolated = true }

[tool.poe.tasks.ty]
cmd = "ty check"
executor = {type = "uv", isolated = true}

[tool.poe.tasks.pyright]
cmd = "pyright"
executor = {type = "uv", isolated = true}

[tool.poe.tasks.mypy]
cmd = "mypy construct_editor"
executor = {type = "uv", isolated = true}

[tool.poe.tasks.typecheck]
sequence = [
{ cmd = "ruff check --fix --show-fixes" },
{ cmd = "ty check" },
{ cmd = "pyright" },
"ty",
"pyright",
"mypy"
]

[tool.poe.tasks.check-all]
sequence = [
"lint",
"typecheck",
"test",
]
executor = {type = "uv", isolated = true}
Loading