Skip to content

Commit 42ebe71

Browse files
committed
Fixed a bug, when a struct has multiple times the same Enum construct. Then the metadata (eg. byte position) of the last parsed enum value is used for all enum values.
1 parent e23edfe commit 42ebe71

5 files changed

Lines changed: 33 additions & 46 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Enhanced ConstructEditor:
1212
- Show full tooltip of the "name" column, which when fields are too long is shown with ellipses. (#18)
1313
- Implemented "Copy" / Ctrl+C (#18)
1414
- Added "Copy path to clipboard" button in the context menu (#18)
15+
- Fixed a bug, when a struct has multiple times the same `Enum` construct. Then the metadata (eg. byte position) of the last parsed enum value is used for all enum values.
1516

1617
Enhanced HexEditor:
1718
- fix crash when selecting or extending selection before the beginning of the hex editor using the shift LEFT and UP arrow keys (#20)

construct_editor/core/preprocessor.py

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import construct as cs
77
import construct_typed as cst
8+
import wrapt
89

910

1011
class GuiMetaData(t.TypedDict):
@@ -15,64 +16,46 @@ class GuiMetaData(t.TypedDict):
1516
child_gui_metadata: t.Optional["GuiMetaData"]
1617

1718

18-
class IntWithGuiMetadata(int):
19-
pass
20-
19+
class ObjProxyWithGuiMetaData(wrapt.ObjectProxy):
20+
__slots__ = "__construct_editor_metadata__"
2121

22-
class FloatWithGuiMetadata(float):
23-
pass
22+
def __init__(self, wrapped: t.Any, gui_metadata: GuiMetaData):
23+
super(ObjProxyWithGuiMetaData, self).__init__(wrapped)
24+
wrapt.ObjectProxy.__setattr__(
25+
self, "__construct_editor_metadata__", gui_metadata
26+
)
2427

2528

2629
class BytesWithGuiMetadata(bytes):
2730
pass
2831

2932

30-
class BytearrayWithGuiMetadata(bytearray):
31-
pass
32-
33-
34-
class StrWithGuiMetadata(str):
35-
pass
36-
37-
38-
class NoneWithGuiMetadata:
39-
pass
40-
41-
4233
def get_gui_metadata(obj: t.Any) -> t.Optional[GuiMetaData]:
4334
"""Get the GUI metadata if they are available"""
4435
try:
45-
return obj.__gui_metadata # type: ignore
36+
return getattr(obj, "__construct_editor_metadata__")
4637
except Exception:
4738
return None
4839

4940

5041
def add_gui_metadata(obj: t.Any, gui_metadata: GuiMetaData) -> t.Any:
51-
"""Append the private field "__gui_metadata" to an object"""
52-
obj_type = type(obj)
53-
if (obj_type is int) or (obj_type is bool):
54-
obj = IntWithGuiMetadata(obj)
55-
obj.__gui_metadata = gui_metadata
56-
elif obj_type is float:
57-
obj = FloatWithGuiMetadata(obj)
58-
obj.__gui_metadata = gui_metadata
59-
elif obj_type is bytes:
42+
"""
43+
Append gui_metadata to an object.
44+
45+
With immutable types like str, bytes, int, ... it is not possible to add
46+
metadata to a type dynammically. With other types like enums it is possible,
47+
but enums are singleton, so that the metadata of objects is overwritten by
48+
the next object with the same value.
49+
50+
Because auf this for any object an proxy object is created, so that the
51+
metadata can be added to this proxy object.
52+
"""
53+
if isinstance(obj, bytes):
54+
# bytes has to be a subtype of bytes or the `stream_write` will raise an error...
6055
obj = BytesWithGuiMetadata(obj)
61-
obj.__gui_metadata = gui_metadata
62-
elif obj_type is bytearray:
63-
obj = BytearrayWithGuiMetadata(obj)
64-
obj.__gui_metadata = gui_metadata
65-
elif obj_type is str:
66-
obj = StrWithGuiMetadata(obj)
67-
obj.__gui_metadata = gui_metadata
68-
elif obj is None:
69-
obj = NoneWithGuiMetadata()
70-
obj.__gui_metadata = gui_metadata
56+
obj.__construct_editor_metadata__ = gui_metadata
7157
else:
72-
try:
73-
obj.__gui_metadata = gui_metadata # type: ignore
74-
except AttributeError:
75-
raise ValueError(f"add_gui_metadata dont work with type of {type(obj)}")
58+
obj = ObjProxyWithGuiMetaData(obj, gui_metadata)
7659
return obj
7760

7861

construct_editor/gallery/test_tflagsenum.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class FlagsEnumTest(cst.DataclassMixin):
8181
permissions: Permission = cst.csfield(cst.TFlagsEnum(cs.Int8ul, Permission))
8282
days: Day = cst.csfield(cst.TFlagsEnum(cs.Int8ul, Day))
8383
long_list: LongList = cst.csfield(cst.TFlagsEnum(cs.Int64ul, LongList))
84+
days2: Day = cst.csfield(cst.TFlagsEnum(cs.Int8ul, Day))
8485

8586

8687
constr = cst.DataclassStruct(FlagsEnumTest)
@@ -93,21 +94,24 @@ class FlagsEnumTest(cst.DataclassMixin):
9394
permissions=Permission.R | Permission.W,
9495
days=Day.Monday | Day.Sunday,
9596
long_list=LongList.Entry49 | LongList.Entry50,
97+
days2=Day.Monday | Day.Sunday,
9698
)
9799
),
98100
"1": constr.build(
99101
FlagsEnumTest(
100102
permissions=Permission.R,
101103
days=Day.Monday,
102104
long_list=LongList.Entry0,
105+
days2=Day.Monday,
103106
)
104107
),
105108
"Zeros": constr.build(
106109
FlagsEnumTest(
107110
permissions=Permission(0),
108111
days=Day(0),
109112
long_list=LongList(0),
113+
days2=Day(0),
110114
)
111115
),
112116
},
113-
)
117+
)

construct_editor/wx_widgets/wx_obj_view.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,6 @@ def __init__(self, parent, settings: ObjViewSettings_Timestamp):
257257
if not isinstance(self.entry.obj, arrow.Arrow):
258258
return
259259

260-
self.obj_type = type(self.entry.obj)
261-
262260
# Obj
263261
hsizer = wx.BoxSizer(wx.HORIZONTAL)
264262
dt = self.entry.obj.datetime
@@ -312,7 +310,7 @@ def __init__(self, parent, settings: ObjViewSettings_Timestamp):
312310
def get_new_obj(self) -> t.Any:
313311
date: wx.DateTime = self.date_picker.GetValue()
314312
time: wx.DateTime = self.time_picker.GetValue()
315-
new_obj = self.obj_type(
313+
new_obj = arrow.Arrow(
316314
year=date.year,
317315
month=date.month + 1, # in wx.adc.DatePickerCtrl the month start with 0
318316
day=date.day,

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
"construct==2.10.68",
3434
"construct-typing==0.5.4",
3535
"wxPython>=4.1.1",
36-
"arrow>=1.0.0"
36+
"arrow>=1.0.0",
37+
"wrapt>=1.14.0"
3738
],
3839
keywords=[
3940
"gui",

0 commit comments

Comments
 (0)