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 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 for a specific fork and preset."""
25
- # Get the specification data
26
- pyspec = get_pyspec()
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
- # Validate that the fork exists
31
- if fork not in pyspec[preset]:
32
- print(f"Error: Fork '{fork}' not found in {preset} preset")
33
- available_forks = list(pyspec[preset].keys())
34
- print(f"Available forks: {', '.join(available_forks)}")
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
- "tags": {
43
- "functions": list(pyspec[preset][fork]['functions'].keys()),
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
- # Plain text output
55
- print(f"Available tags for {fork} fork ({preset} preset):")
56
- maybe_fork = f' fork="{fork}"' if fork != get_latest_fork() else ""
57
-
58
- print("\nFunctions:")
59
- for fn_name in sorted(pyspec[preset][fork]['functions'].keys()):
60
- if args.search is None or args.search.lower() in fn_name.lower():
61
- print(f" <spec fn=\"{fn_name}\"{maybe_fork} />")
62
-
63
- print("\nConstants:")
64
- for const_name in sorted(pyspec[preset][fork]['constant_vars'].keys()):
65
- if args.search is None or args.search.lower() in const_name.lower():
66
- print(f" <spec constant_var=\"{const_name}\"{maybe_fork} />")
67
-
68
- print("\nCustom Types:")
69
- for type_name in sorted(pyspec[preset][fork]['custom_types'].keys()):
70
- if args.search is None or args.search.lower() in type_name.lower():
71
- print(f" <spec custom_type=\"{type_name}\"{maybe_fork} />")
72
-
73
- print("\nSSZ Objects:")
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
- # Put phase0 at the top & EIP feature forks at the bottom
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
- previous_forks.append(f)
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.startswith("eip"), x)
206
+ [fork for fork in pyspec["mainnet"].keys() if not fork.startswith("eip")],
207
+ key=lambda x: (x != "phase0", x)
206
208
  )
207
- for fork in reversed(forks):
208
- if not fork.startswith("eip"):
209
- return fork
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ethspecify
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A utility for processing Ethereum specification tags.
5
5
  Home-page: https://github.com/jtraglia/ethspecify
6
6
  Author: Justin Traglia
@@ -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,,