ethspecify 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl
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.
Potentially problematic release.
This version of ethspecify might be problematic. Click here for more details.
- ethspecify/cli.py +39 -76
- ethspecify/core.py +146 -6
- {ethspecify-0.2.1.dist-info → ethspecify-0.2.2.dist-info}/METADATA +1 -1
- ethspecify-0.2.2.dist-info/RECORD +9 -0
- ethspecify-0.2.1.dist-info/RECORD +0 -9
- {ethspecify-0.2.1.dist-info → ethspecify-0.2.2.dist-info}/WHEEL +0 -0
- {ethspecify-0.2.1.dist-info → ethspecify-0.2.2.dist-info}/entry_points.txt +0 -0
- {ethspecify-0.2.1.dist-info → ethspecify-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {ethspecify-0.2.1.dist-info → ethspecify-0.2.2.dist-info}/top_level.txt +0 -0
ethspecify/cli.py
CHANGED
|
@@ -3,7 +3,7 @@ import json
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
-
from .core import grep, replace_spec_tags, get_pyspec, get_latest_fork
|
|
6
|
+
from .core import grep, replace_spec_tags, get_pyspec, get_latest_fork, get_spec_item_history
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def process(args):
|
|
@@ -21,78 +21,53 @@ def process(args):
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def list_tags(args):
|
|
24
|
-
"""List all available tags
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
fork = args.fork
|
|
28
|
-
preset = args.preset
|
|
24
|
+
"""List all available tags with their fork history."""
|
|
25
|
+
preset = getattr(args, 'preset', 'mainnet')
|
|
26
|
+
return _list_tags_with_history(args, preset)
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
|
|
29
|
+
def _list_tags_with_history(args, preset):
|
|
30
|
+
"""List all tags with their fork history."""
|
|
31
|
+
try:
|
|
32
|
+
history = get_spec_item_history(preset)
|
|
33
|
+
except ValueError as e:
|
|
34
|
+
print(f"Error: {e}")
|
|
35
35
|
return 1
|
|
36
36
|
|
|
37
|
-
# Format output based on requested format
|
|
38
37
|
if args.format == "json":
|
|
39
38
|
result = {
|
|
40
|
-
"fork": fork,
|
|
41
39
|
"preset": preset,
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
"constant_vars": list(pyspec[preset][fork]['constant_vars'].keys()),
|
|
45
|
-
"custom_types": list(pyspec[preset][fork]['custom_types'].keys()),
|
|
46
|
-
"ssz_objects": list(pyspec[preset][fork]['ssz_objects'].keys()),
|
|
47
|
-
"dataclasses": list(pyspec[preset][fork]['dataclasses'].keys()),
|
|
48
|
-
"preset_vars": list(pyspec[preset][fork]['preset_vars'].keys()),
|
|
49
|
-
"config_vars": list(pyspec[preset][fork]['config_vars'].keys()),
|
|
50
|
-
}
|
|
40
|
+
"mode": "history",
|
|
41
|
+
"history": history
|
|
51
42
|
}
|
|
52
43
|
print(json.dumps(result, indent=2))
|
|
53
44
|
else:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
for obj_name in sorted(pyspec[preset][fork]['ssz_objects'].keys()):
|
|
75
|
-
if args.search is None or args.search.lower() in obj_name.lower():
|
|
76
|
-
print(f" <spec ssz_object=\"{obj_name}\"{maybe_fork} />")
|
|
77
|
-
|
|
78
|
-
print("\nDataclasses:")
|
|
79
|
-
for class_name in sorted(pyspec[preset][fork]['dataclasses'].keys()):
|
|
80
|
-
if args.search is None or args.search.lower() in class_name.lower():
|
|
81
|
-
print(f" <spec dataclass=\"{class_name}\"{maybe_fork} />")
|
|
82
|
-
|
|
83
|
-
print("\nPreset Variables:")
|
|
84
|
-
for var_name in sorted(pyspec[preset][fork]['preset_vars'].keys()):
|
|
85
|
-
if args.search is None or args.search.lower() in var_name.lower():
|
|
86
|
-
print(f" <spec preset_var=\"{var_name}\"{maybe_fork} />")
|
|
87
|
-
|
|
88
|
-
print("\nConfig Variables:")
|
|
89
|
-
for var_name in sorted(pyspec[preset][fork]['config_vars'].keys()):
|
|
90
|
-
if args.search is None or args.search.lower() in var_name.lower():
|
|
91
|
-
print(f" <spec config_var=\"{var_name}\"{maybe_fork} />")
|
|
45
|
+
print(f"Available tags across all forks ({preset} preset):")
|
|
46
|
+
|
|
47
|
+
def _print_items_with_history(category_name, items_dict, spec_attr):
|
|
48
|
+
"""Helper to print items with their fork history."""
|
|
49
|
+
if not items_dict:
|
|
50
|
+
return
|
|
51
|
+
print(f"\n{category_name}:")
|
|
52
|
+
for item_name in sorted(items_dict.keys()):
|
|
53
|
+
if args.search is None or args.search.lower() in item_name.lower():
|
|
54
|
+
forks = items_dict[item_name]
|
|
55
|
+
fork_list = ", ".join(forks)
|
|
56
|
+
print(f" <spec {spec_attr}=\"{item_name}\" /> ({fork_list})")
|
|
57
|
+
|
|
58
|
+
_print_items_with_history("Functions", history['functions'], "fn")
|
|
59
|
+
_print_items_with_history("Constants", history['constant_vars'], "constant_var")
|
|
60
|
+
_print_items_with_history("Custom Types", history['custom_types'], "custom_type")
|
|
61
|
+
_print_items_with_history("SSZ Objects", history['ssz_objects'], "ssz_object")
|
|
62
|
+
_print_items_with_history("Dataclasses", history['dataclasses'], "dataclass")
|
|
63
|
+
_print_items_with_history("Preset Variables", history['preset_vars'], "preset_var")
|
|
64
|
+
_print_items_with_history("Config Variables", history['config_vars'], "config_var")
|
|
92
65
|
|
|
93
66
|
return 0
|
|
94
67
|
|
|
95
68
|
|
|
69
|
+
|
|
70
|
+
|
|
96
71
|
def list_forks(args):
|
|
97
72
|
"""List all available forks."""
|
|
98
73
|
pyspec = get_pyspec()
|
|
@@ -103,10 +78,10 @@ def list_forks(args):
|
|
|
103
78
|
print(f"Available presets: {', '.join(pyspec.keys())}")
|
|
104
79
|
return 1
|
|
105
80
|
|
|
81
|
+
# Filter out EIP forks
|
|
106
82
|
forks = sorted(
|
|
107
|
-
pyspec[preset].keys(),
|
|
108
|
-
|
|
109
|
-
key=lambda x: (x != "phase0", x.startswith("eip"), x)
|
|
83
|
+
[fork for fork in pyspec[preset].keys() if not fork.startswith("eip")],
|
|
84
|
+
key=lambda x: (x != "phase0", x)
|
|
110
85
|
)
|
|
111
86
|
|
|
112
87
|
if args.format == "json":
|
|
@@ -148,20 +123,8 @@ def main():
|
|
|
148
123
|
)
|
|
149
124
|
|
|
150
125
|
# Parser for 'list-tags' command
|
|
151
|
-
list_tags_parser = subparsers.add_parser("list-tags", help="List available specification tags")
|
|
126
|
+
list_tags_parser = subparsers.add_parser("list-tags", help="List available specification tags with fork history")
|
|
152
127
|
list_tags_parser.set_defaults(func=list_tags)
|
|
153
|
-
list_tags_parser.add_argument(
|
|
154
|
-
"--fork",
|
|
155
|
-
type=str,
|
|
156
|
-
help="Fork to list tags for",
|
|
157
|
-
default=get_latest_fork(),
|
|
158
|
-
)
|
|
159
|
-
list_tags_parser.add_argument(
|
|
160
|
-
"--preset",
|
|
161
|
-
type=str,
|
|
162
|
-
help="Preset to use (mainnet or minimal)",
|
|
163
|
-
default="mainnet",
|
|
164
|
-
)
|
|
165
128
|
list_tags_parser.add_argument(
|
|
166
129
|
"--format",
|
|
167
130
|
type=str,
|
ethspecify/core.py
CHANGED
|
@@ -107,7 +107,9 @@ def get_previous_forks(fork, version="nightly"):
|
|
|
107
107
|
if key != f"{fork.upper()}_FORK_VERSION":
|
|
108
108
|
if key != "GENESIS_FORK_VERSION":
|
|
109
109
|
f = key.split("_")[0].lower()
|
|
110
|
-
|
|
110
|
+
# Skip EIP forks
|
|
111
|
+
if not f.startswith("eip"):
|
|
112
|
+
previous_forks.append(f)
|
|
111
113
|
return list(reversed(previous_forks))
|
|
112
114
|
|
|
113
115
|
|
|
@@ -201,12 +203,150 @@ def get_latest_fork(version="nightly"):
|
|
|
201
203
|
"""A helper function to get the latest non-eip fork."""
|
|
202
204
|
pyspec = get_pyspec(version)
|
|
203
205
|
forks = sorted(
|
|
204
|
-
pyspec["mainnet"].keys(),
|
|
205
|
-
key=lambda x: (x != "phase0", x
|
|
206
|
+
[fork for fork in pyspec["mainnet"].keys() if not fork.startswith("eip")],
|
|
207
|
+
key=lambda x: (x != "phase0", x)
|
|
206
208
|
)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
return forks[-1] if forks else "phase0"
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def get_spec_item_changes(fork, preset="mainnet", version="nightly"):
|
|
213
|
+
"""
|
|
214
|
+
Compare spec items in the given fork with previous forks to detect changes.
|
|
215
|
+
Returns dict with categories containing items marked as (new) or (modified).
|
|
216
|
+
"""
|
|
217
|
+
pyspec = get_pyspec(version)
|
|
218
|
+
if fork not in pyspec[preset]:
|
|
219
|
+
raise ValueError(f"Fork '{fork}' not found in {preset} preset")
|
|
220
|
+
|
|
221
|
+
current_fork_data = pyspec[preset][fork]
|
|
222
|
+
previous_forks = get_previous_forks(fork, version)
|
|
223
|
+
|
|
224
|
+
changes = {
|
|
225
|
+
'functions': {},
|
|
226
|
+
'constant_vars': {},
|
|
227
|
+
'custom_types': {},
|
|
228
|
+
'ssz_objects': {},
|
|
229
|
+
'dataclasses': {},
|
|
230
|
+
'preset_vars': {},
|
|
231
|
+
'config_vars': {},
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# Check each category of spec items
|
|
235
|
+
for category in changes.keys():
|
|
236
|
+
if category not in current_fork_data:
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
for item_name, item_content in current_fork_data[category].items():
|
|
240
|
+
status = _get_item_status(item_name, item_content, category, previous_forks, pyspec, preset)
|
|
241
|
+
if status:
|
|
242
|
+
changes[category][item_name] = status
|
|
243
|
+
|
|
244
|
+
return changes
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _get_item_status(item_name, current_content, category, previous_forks, pyspec, preset):
|
|
248
|
+
"""
|
|
249
|
+
Determine if an item is new or modified compared to previous forks.
|
|
250
|
+
Returns 'new', 'modified', or None if unchanged.
|
|
251
|
+
"""
|
|
252
|
+
# Check if item exists in any previous fork
|
|
253
|
+
found_in_previous = False
|
|
254
|
+
previous_content = None
|
|
255
|
+
|
|
256
|
+
for prev_fork in previous_forks:
|
|
257
|
+
if (prev_fork in pyspec[preset] and
|
|
258
|
+
category in pyspec[preset][prev_fork] and
|
|
259
|
+
item_name in pyspec[preset][prev_fork][category]):
|
|
260
|
+
|
|
261
|
+
found_in_previous = True
|
|
262
|
+
prev_content = pyspec[preset][prev_fork][category][item_name]
|
|
263
|
+
|
|
264
|
+
# Compare content with immediate previous version
|
|
265
|
+
if prev_content != current_content:
|
|
266
|
+
return "modified"
|
|
267
|
+
else:
|
|
268
|
+
# Found unchanged version, so this is not new or modified
|
|
269
|
+
return None
|
|
270
|
+
|
|
271
|
+
# If not found in any previous fork, it's new
|
|
272
|
+
if not found_in_previous:
|
|
273
|
+
return "new"
|
|
274
|
+
|
|
275
|
+
return None
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def get_spec_item_history(preset="mainnet", version="nightly"):
|
|
279
|
+
"""
|
|
280
|
+
Get the complete history of all spec items across all forks.
|
|
281
|
+
Returns dict with categories containing items and their fork history.
|
|
282
|
+
"""
|
|
283
|
+
pyspec = get_pyspec(version)
|
|
284
|
+
if preset not in pyspec:
|
|
285
|
+
raise ValueError(f"Preset '{preset}' not found")
|
|
286
|
+
|
|
287
|
+
# Get all forks in chronological order, excluding EIP forks
|
|
288
|
+
all_forks = sorted(
|
|
289
|
+
[fork for fork in pyspec[preset].keys() if not fork.startswith("eip")],
|
|
290
|
+
key=lambda x: (x != "phase0", x)
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# Track all unique items across all forks
|
|
294
|
+
all_items = {
|
|
295
|
+
'functions': set(),
|
|
296
|
+
'constant_vars': set(),
|
|
297
|
+
'custom_types': set(),
|
|
298
|
+
'ssz_objects': set(),
|
|
299
|
+
'dataclasses': set(),
|
|
300
|
+
'preset_vars': set(),
|
|
301
|
+
'config_vars': set(),
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
# Collect all item names
|
|
305
|
+
for fork in all_forks:
|
|
306
|
+
if fork not in pyspec[preset]:
|
|
307
|
+
continue
|
|
308
|
+
fork_data = pyspec[preset][fork]
|
|
309
|
+
for category in all_items.keys():
|
|
310
|
+
if category in fork_data:
|
|
311
|
+
all_items[category].update(fork_data[category].keys())
|
|
312
|
+
|
|
313
|
+
# Build history for each item
|
|
314
|
+
history = {}
|
|
315
|
+
for category in all_items.keys():
|
|
316
|
+
history[category] = {}
|
|
317
|
+
for item_name in all_items[category]:
|
|
318
|
+
item_history = _trace_item_history(item_name, category, all_forks, pyspec, preset)
|
|
319
|
+
if item_history:
|
|
320
|
+
history[category][item_name] = item_history
|
|
321
|
+
|
|
322
|
+
return history
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _trace_item_history(item_name, category, all_forks, pyspec, preset):
|
|
326
|
+
"""
|
|
327
|
+
Trace the history of a specific item across all forks.
|
|
328
|
+
Returns a list of forks where the item was introduced or modified.
|
|
329
|
+
"""
|
|
330
|
+
history_forks = []
|
|
331
|
+
previous_content = None
|
|
332
|
+
|
|
333
|
+
for fork in all_forks:
|
|
334
|
+
if (fork in pyspec[preset] and
|
|
335
|
+
category in pyspec[preset][fork] and
|
|
336
|
+
item_name in pyspec[preset][fork][category]):
|
|
337
|
+
|
|
338
|
+
current_content = pyspec[preset][fork][category][item_name]
|
|
339
|
+
|
|
340
|
+
if previous_content is None:
|
|
341
|
+
# First appearance
|
|
342
|
+
history_forks.append(fork)
|
|
343
|
+
elif current_content != previous_content:
|
|
344
|
+
# Content changed
|
|
345
|
+
history_forks.append(fork)
|
|
346
|
+
|
|
347
|
+
previous_content = current_content
|
|
348
|
+
|
|
349
|
+
return history_forks
|
|
210
350
|
|
|
211
351
|
def parse_common_attributes(attributes):
|
|
212
352
|
try:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
ethspecify/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
ethspecify/cli.py,sha256=wkJyDd55peeJjNe1vF8suje3Mc6ggEa3O6hvfGUZSD4,5162
|
|
3
|
+
ethspecify/core.py,sha256=7H1mwkQ2YBxJbO-RCc-7RCy6cJoxFnWwfe-H9McUwaU,17881
|
|
4
|
+
ethspecify-0.2.2.dist-info/licenses/LICENSE,sha256=Awxsr73mm9YMBVhBYnzeI7bNdRd-bH6RDtO5ItG0DaM,1071
|
|
5
|
+
ethspecify-0.2.2.dist-info/METADATA,sha256=NT3bYROThPVfEI6LNWMOCjh12b-6GNrgY5s6uhjm1io,9185
|
|
6
|
+
ethspecify-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
ethspecify-0.2.2.dist-info/entry_points.txt,sha256=09viGkCg9J3h0c9BFRN-BKaJUEaIc4JyULNgBP5EL_g,51
|
|
8
|
+
ethspecify-0.2.2.dist-info/top_level.txt,sha256=0klaMvlVyOkXW09fwZTijJpdybITEp2c9zQKV5v30VM,11
|
|
9
|
+
ethspecify-0.2.2.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
ethspecify/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
ethspecify/cli.py,sha256=73NnY6-xvFcxMnpeZ1LqvU02EiNiPx5jOor1KPERenk,6903
|
|
3
|
-
ethspecify/core.py,sha256=Nu5-onBdtmibdO9FkwZL1gGWjRAvZkTPeWZ0H9v2NoI,13292
|
|
4
|
-
ethspecify-0.2.1.dist-info/licenses/LICENSE,sha256=Awxsr73mm9YMBVhBYnzeI7bNdRd-bH6RDtO5ItG0DaM,1071
|
|
5
|
-
ethspecify-0.2.1.dist-info/METADATA,sha256=qYoT3-9O7b2SbY7mDJrDJo7T--VpjkIJTPrD2Ob03rc,9185
|
|
6
|
-
ethspecify-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
ethspecify-0.2.1.dist-info/entry_points.txt,sha256=09viGkCg9J3h0c9BFRN-BKaJUEaIc4JyULNgBP5EL_g,51
|
|
8
|
-
ethspecify-0.2.1.dist-info/top_level.txt,sha256=0klaMvlVyOkXW09fwZTijJpdybITEp2c9zQKV5v30VM,11
|
|
9
|
-
ethspecify-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|