obstruct 0.2.14__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/workspace.xml +42 -3
  2. {obstruct-0.2.14 → obstruct-0.3.0}/PKG-INFO +1 -1
  3. obstruct-0.3.0/src/obstruct/__version__.py +1 -0
  4. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/aot/base.py +5 -2
  5. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/aot/unpack.py +62 -35
  6. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/struct_type.py +7 -0
  7. {obstruct-0.2.14 → obstruct-0.3.0}/test/test_speed.py +32 -29
  8. obstruct-0.2.14/src/obstruct/__version__.py +0 -1
  9. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/.gitignore +0 -0
  10. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/inspectionProfiles/Project_Default.xml +0 -0
  11. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/inspectionProfiles/profiles_settings.xml +0 -0
  12. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/misc.xml +0 -0
  13. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/modules.xml +0 -0
  14. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/obstruct.iml +0 -0
  15. {obstruct-0.2.14 → obstruct-0.3.0}/.idea/vcs.xml +0 -0
  16. {obstruct-0.2.14 → obstruct-0.3.0}/README.md +0 -0
  17. {obstruct-0.2.14 → obstruct-0.3.0}/pyproject.toml +0 -0
  18. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/__init__.py +0 -0
  19. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/aot/__init__.py +0 -0
  20. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/aot/aot.py +0 -0
  21. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/aot/pack.py +0 -0
  22. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/metadata_marks.py +0 -0
  23. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/methods.py +0 -0
  24. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/types/__init__.py +0 -0
  25. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/types/base.py +0 -0
  26. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/types/types.py +0 -0
  27. {obstruct-0.2.14 → obstruct-0.3.0}/src/obstruct/types/types.pyi +0 -0
  28. {obstruct-0.2.14 → obstruct-0.3.0}/test/test.py +0 -0
  29. {obstruct-0.2.14 → obstruct-0.3.0}/uv.lock +0 -0
@@ -4,7 +4,11 @@
4
4
  <option name="autoReloadType" value="SELECTIVE" />
5
5
  </component>
6
6
  <component name="ChangeListManager">
7
- <list default="true" id="b482b6b4-48ce-4be1-bf3c-a72ec254fa35" name="更改" comment="chore: 更新项目信息和 README 文档" />
7
+ <list default="true" id="b482b6b4-48ce-4be1-bf3c-a72ec254fa35" name="更改" comment="fix: 更新版本号至 0.2.15,修复延迟加载不会应用到类属性的问题">
8
+ <change beforePath="$PROJECT_DIR$/src/obstruct/aot/base.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/base.py" afterDir="false" />
9
+ <change beforePath="$PROJECT_DIR$/src/obstruct/aot/unpack.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/obstruct/aot/unpack.py" afterDir="false" />
10
+ <change beforePath="$PROJECT_DIR$/test/test_speed.py" beforeDir="false" afterPath="$PROJECT_DIR$/test/test_speed.py" afterDir="false" />
11
+ </list>
8
12
  <option name="SHOW_DIALOG" value="false" />
9
13
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
10
14
  <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@@ -252,7 +256,39 @@
252
256
  <option name="project" value="LOCAL" />
253
257
  <updated>1786969506672</updated>
254
258
  </task>
255
- <option name="localTasksCounter" value="16" />
259
+ <task id="LOCAL-00016" summary="fix: 更新版本号至 0.2.13,修复类变量识别错误的问题">
260
+ <option name="closed" value="true" />
261
+ <created>1786969885468</created>
262
+ <option name="number" value="00016" />
263
+ <option name="presentableId" value="LOCAL-00016" />
264
+ <option name="project" value="LOCAL" />
265
+ <updated>1786969885469</updated>
266
+ </task>
267
+ <task id="LOCAL-00017" summary="fix: 更新版本号至 0.2.13,修复类变量识别错误的问题">
268
+ <option name="closed" value="true" />
269
+ <created>1786969895079</created>
270
+ <option name="number" value="00017" />
271
+ <option name="presentableId" value="LOCAL-00017" />
272
+ <option name="project" value="LOCAL" />
273
+ <updated>1786969895079</updated>
274
+ </task>
275
+ <task id="LOCAL-00018" summary="fix: 更新版本号至 0.2.14,修复 __cendian__ 类变量识别错误的问题">
276
+ <option name="closed" value="true" />
277
+ <created>1786969988797</created>
278
+ <option name="number" value="00018" />
279
+ <option name="presentableId" value="LOCAL-00018" />
280
+ <option name="project" value="LOCAL" />
281
+ <updated>1786969988797</updated>
282
+ </task>
283
+ <task id="LOCAL-00019" summary="fix: 更新版本号至 0.2.15,修复延迟加载不会应用到类属性的问题">
284
+ <option name="closed" value="true" />
285
+ <created>1786971691114</created>
286
+ <option name="number" value="00019" />
287
+ <option name="presentableId" value="LOCAL-00019" />
288
+ <option name="project" value="LOCAL" />
289
+ <updated>1786971691114</updated>
290
+ </task>
291
+ <option name="localTasksCounter" value="20" />
256
292
  <servers />
257
293
  </component>
258
294
  <component name="TypeScriptGeneratedFilesManager">
@@ -285,6 +321,9 @@
285
321
  <MESSAGE value="feat: 更新版本号(跳过一次版本号更改),添加 NOT_A_FIELD 标记控制一个字段是否该被当作二进制字段解析" />
286
322
  <MESSAGE value="feat: 更新版本号,添加一些更加清晰明确的类型别名" />
287
323
  <MESSAGE value="chore: 更新项目信息和 README 文档" />
288
- <option name="LAST_COMMIT_MESSAGE" value="chore: 更新项目信息和 README 文档" />
324
+ <MESSAGE value="fix: 更新版本号至 0.2.13,修复类变量识别错误的问题" />
325
+ <MESSAGE value="fix: 更新版本号至 0.2.14,修复 __cendian__ 类变量识别错误的问题" />
326
+ <MESSAGE value="fix: 更新版本号至 0.2.15,修复延迟加载不会应用到类属性的问题" />
327
+ <option name="LAST_COMMIT_MESSAGE" value="fix: 更新版本号至 0.2.15,修复延迟加载不会应用到类属性的问题" />
289
328
  </component>
290
329
  </project>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: obstruct
3
- Version: 0.2.14
3
+ Version: 0.3.0
4
4
  Author-email: LittleNightSong <LittleNightSongYO@outlook.com>
5
5
  Classifier: Development Status :: 3 - Alpha
6
6
  Classifier: Programming Language :: Python
@@ -0,0 +1 @@
1
+ version = "0.3.0"
@@ -5,6 +5,8 @@ import itertools
5
5
  import typing
6
6
  from typing import Any
7
7
 
8
+ if typing.TYPE_CHECKING:
9
+ from obstruct import Struct
8
10
 
9
11
 
10
12
  class _objective_node_operator:
@@ -121,8 +123,9 @@ def unique_name_generator():
121
123
  itertools.combinations(available_characters, cnt))
122
124
 
123
125
 
124
- def is_struct(tp):
125
- return hasattr(tp, '__cstruct__')
126
+ def is_struct(tp) -> typing.TypeIs[type[Struct]]:
127
+ from obstruct.struct_type import Struct
128
+ return isinstance(tp, type) and issubclass(tp, Struct)
126
129
 
127
130
 
128
131
  def is_array(tp):
@@ -7,10 +7,14 @@ import typing
7
7
  from .base import unique_name_generator, is_struct, is_array, get_array_ctype, function_def, for_stmt, get_array_length
8
8
 
9
9
  if typing.TYPE_CHECKING:
10
- from .. import struct_type
10
+ from obstruct.struct_type import Struct
11
11
 
12
12
 
13
- def create_unpack_methods(cls: type[struct_type.Struct]):
13
+ def batch_add_code(objs, code: str):
14
+ for obj in objs:
15
+ obj.add_code(code)
16
+
17
+ def create_unpack_methods(cls: type[Struct]):
14
18
  from ..methods import get_ctype
15
19
 
16
20
  with (
@@ -52,58 +56,74 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
52
56
  iter_update.add_node(iter_update_inner.node)
53
57
 
54
58
  array_fields = []
55
-
56
- def walk(fields, path, parent_name=None, current_class_name='cls', offset=0):
57
- name = 'self'
58
-
59
- if len(path) > 1: # 在处理内嵌的结构体
60
- name = next(ung) # 临时变量的名称
61
- update_add_code(f"{name} = {parent_name}.{path[-1]}")
62
-
63
- unpack_add_code(f"{parent_name}.{path[-1]} = {name} = __new__({current_class_name})") # 组合赋值
59
+ post_inits = []
60
+
61
+ def walk(
62
+ struct_type: type[Struct],
63
+ absolute_xpath: tuple[str, ...],
64
+ current_xname: str = 'self',
65
+ parent_xname=None,
66
+ current_type_name='cls',
67
+ offset=0
68
+ ):
69
+ name = current_xname
70
+
71
+ if len(absolute_xpath) > 1: # 在处理内嵌的结构体
72
+ current_field_name = absolute_xpath[-1]
73
+ update_add_code(f"{name} = {parent_xname}.{current_field_name}")
74
+ unpack_add_code(f"{parent_xname}.{current_field_name} = {name} = __new__({current_type_name})") # 组合赋值
64
75
  else:
65
- unpack_add_code(f"{name} = __new__({current_class_name})") # 不需要临时变量存储根对象
76
+ unpack_add_code(f"{name} = __new__({current_type_name})") # 不需要临时变量存储根对象
66
77
  # update 在这里不需要创建新对象
67
78
 
79
+ fields = struct_type.__cfields__
80
+
68
81
  for field in fields: # 遍历字段
69
82
  field_xpath = f'{name}.{field.name}'
70
83
 
71
- # ctype = get_ctype(field.type)
72
- # print(f"当前字段:{field_xpath},类型:{field.type} '{ctype}',偏移量:{offset}+{struct.calcsize(ctype)}")
73
-
74
84
  if is_struct(field.type): # 是个内嵌的结构体
75
85
  if field.type not in inner_classes: # 如果这个内嵌的结构体类型不在已知的结构体中(没有分配类名称)
76
86
  type_name = next(ung) # 生成一个唯一的类名
77
- inner_classes[field.type] = type_name # 添加
87
+ inner_classes[field.type] = type_name
78
88
  else:
79
89
  type_name = inner_classes[field.type] # 如果在,那么提取
80
90
 
81
- walk(field.type.__cfields__, path + (field.name,), name, type_name, offset)
91
+ field_xname = next(ung)
92
+ walk(
93
+ field.type,
94
+ absolute_xpath + (field.name,),
95
+ field_xname,
96
+ name,
97
+ type_name,
98
+ offset
99
+ )
82
100
  offset += field.type.__cstruct__.size
83
101
 
84
- elif is_array(field.type):
85
- dtype = get_array_ctype(field.type)
86
- nbytes = get_array_length(field.type) * struct.calcsize(dtype)
87
- array_fields.append((next(ung), field_xpath, dtype, offset, nbytes))
88
- offset += nbytes
89
- else:
102
+ post_inits.append(field_xname)
103
+
104
+ elif is_array(field.type): # 如果是一个数组类型
105
+ dtype = get_array_ctype(field.type) # 获取内容数据类型
106
+ nbytes = get_array_length(field.type) * struct.calcsize(dtype) # 计算数组实际大小
107
+ array_fields.append((next(ung), field_xpath, dtype, offset, nbytes)) # 记录这个数组
108
+ offset += nbytes # 增加当前偏移量
109
+
110
+ else: # 不是特殊的类型,正常处理(添加 assign 目标,并增加偏移量)
90
111
  assigns.append(field_xpath)
91
112
  offset += struct.calcsize(get_ctype(field.type))
92
113
 
93
- walk(cls.__cfields__, ('A',))
114
+ walk(cls, ('A',))
94
115
 
95
- assign_code = f"{', '.join(assigns)} = _unpack(buffer)" # 生成普通的 unpack, update 用的赋值语句
116
+ assigns_expr = ', '.join(assigns)
117
+ assign_code = f"{assigns_expr} = _unpack(buffer)" # 生成普通的 unpack, update 用的赋值语句
96
118
  # {assigns} = _unpack(buffer)
97
119
  unpack.add_code(assign_code)
98
120
  update.add_code(assign_code)
99
121
 
100
- assign_code = assign_code.replace("_unpack(buffer)", "values") # 生成 iter_xxx 的赋值语句
101
- # {assigns} = values
122
+ assign_code = f"{assigns_expr} = values" # 生成 iter_xxx 的赋值语句
102
123
  iter_unpack_inner.add_code(assign_code)
103
124
  iter_update_inner.add_code(assign_code)
104
125
 
105
- assign_code = assign_code.replace("values", "_unpack_from(buffer, offset)") # 生成 xxx_from 的赋值语句
106
- # {assigns} = _unpack_from(buffer, offset)
126
+ assign_code = f"{assigns_expr} = _unpack_from(buffer, offset)" # 生成 xxx_from 的赋值语句
107
127
  unpack_from.add_code(assign_code)
108
128
  update_from.add_code(assign_code)
109
129
 
@@ -145,6 +165,13 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
145
165
  if array_fields:
146
166
  unpack.insert_code(0, 'buffer = memoryview(buffer)')
147
167
 
168
+
169
+ for init in post_inits:
170
+ batch_add_code(
171
+ [unpack, update, unpack_from, update_from, iter_unpack_inner, iter_update_inner],
172
+ f"{init}.__post_unpack__()"
173
+ )
174
+
148
175
  unpack.add_return('self')
149
176
  update.add_return('self')
150
177
  unpack_from.add_return('self')
@@ -156,12 +183,12 @@ def create_unpack_methods(cls: type[struct_type.Struct]):
156
183
  for n, *_ in array_fields:
157
184
  iter_update_inner.add_code(f'{n}.clear()')
158
185
 
159
- # print(unpack.generate_code())
160
- # print(update.generate_code())
161
- # print(unpack_from.generate_code())
162
- # print(update_from.generate_code())
163
- # print(iter_unpack.generate_code())
164
- # print(iter_update.generate_code())
186
+ print(unpack.generate_code())
187
+ print(update.generate_code())
188
+ print(unpack_from.generate_code())
189
+ print(update_from.generate_code())
190
+ print(iter_unpack.generate_code())
191
+ print(iter_update.generate_code())
165
192
 
166
193
  globals = {
167
194
  v: k for k, v in inner_classes.items() # 翻转字典
@@ -81,6 +81,13 @@ class StructMeta(type):
81
81
  create_unpack_methods(cls)
82
82
  )
83
83
 
84
+ def __getattr__(self, item):
85
+ if item in self.__struct_methods__:
86
+ self.__compile_struct__()
87
+ return getattr(self, item)
88
+
89
+ raise AttributeError(item)
90
+
84
91
 
85
92
  endian_mapping = {
86
93
  'little': '<',
@@ -21,6 +21,9 @@ class MyStruct(obs.Struct):
21
21
  k: obs.unsigned_char
22
22
  l: obs.long_long
23
23
 
24
+ def __post_unpack__(self):
25
+ ...
26
+
24
27
 
25
28
  @dataclasses.dataclass()
26
29
  class AnotherStruct(obs.Struct):
@@ -36,15 +39,15 @@ print('MyStruct size', MyStruct.__cstruct__.size)
36
39
  print('AnotherStruct size', AnotherStruct.__cstruct__.size)
37
40
 
38
41
 
39
- data = MyStruct(
40
- 1,2,1.0,4,5,6,7,8,9,b'8',1,2
41
- )
42
-
43
- packed_data = data.pack()
42
+ # data = MyStruct(
43
+ # 1,2,1.0,4,5,6,7,8,9,b'8',1,2
44
+ # )
45
+ #
46
+ # packed_data = data.pack()
44
47
 
45
48
 
46
- complex_data = AnotherStruct(data, array('i', [100]*100), data)
47
- packed_complex_data = complex_data.pack()
49
+ # complex_data = AnotherStruct(data, array('i', [100]*100), data)
50
+ # packed_complex_data = complex_data.pack()
48
51
 
49
52
 
50
53
  def test_timeit(name, code):
@@ -71,31 +74,31 @@ def test_timeit(name, code):
71
74
  print(f'Average: {sum(res)/(len(res))/NUMBER:.3f} ns per step', '\n\n')
72
75
 
73
76
 
74
- print("\n\nMyStruct:", MyStruct.__cstruct__.size)
77
+ # print("\n\nMyStruct:", MyStruct.__cstruct__.size)
75
78
  print("AnotherStruct:", AnotherStruct.__cstruct__.size, '\n\n')
76
79
 
77
80
  NUMBER = 10000
78
81
  REPEAT = 128
79
82
  SORT = 32
80
83
 
81
- test_timeit(
82
- name='Pack',
83
- code="""data.pack()""",
84
- )
85
-
86
- test_timeit(
87
- name='Unpack',
88
- code="""MyStruct.unpack(packed_data)""",
89
- )
90
-
91
-
92
-
93
- test_timeit(
94
- name='Complex Pack',
95
- code="""complex_data.pack()""",
96
- )
97
-
98
- test_timeit(
99
- name='Complex Unpack',
100
- code="""AnotherStruct.unpack(packed_complex_data)""",
101
- )
84
+ # test_timeit(
85
+ # name='Pack',
86
+ # code="""data.pack()""",
87
+ # )
88
+ #
89
+ # test_timeit(
90
+ # name='Unpack',
91
+ # code="""MyStruct.unpack(packed_data)""",
92
+ # )
93
+ #
94
+ #
95
+ #
96
+ # test_timeit(
97
+ # name='Complex Pack',
98
+ # code="""complex_data.pack()""",
99
+ # )
100
+ #
101
+ # test_timeit(
102
+ # name='Complex Unpack',
103
+ # code="""AnotherStruct.unpack(packed_complex_data)""",
104
+ # )
@@ -1 +0,0 @@
1
- version = "0.2.14"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes