ethspecify 0.2.1__tar.gz → 0.2.3__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.
Potentially problematic release.
This version of ethspecify might be problematic. Click here for more details.
- {ethspecify-0.2.1 → ethspecify-0.2.3}/PKG-INFO +2 -1
- ethspecify-0.2.3/ethspecify/cli.py +239 -0
- ethspecify-0.2.3/ethspecify/core.py +951 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/ethspecify.egg-info/PKG-INFO +2 -1
- {ethspecify-0.2.1 → ethspecify-0.2.3}/ethspecify.egg-info/requires.txt +1 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/setup.py +2 -1
- ethspecify-0.2.1/ethspecify/cli.py +0 -205
- ethspecify-0.2.1/ethspecify/core.py +0 -356
- {ethspecify-0.2.1 → ethspecify-0.2.3}/LICENSE +0 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/README.md +0 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/ethspecify/__init__.py +0 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/ethspecify.egg-info/SOURCES.txt +0 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/ethspecify.egg-info/dependency_links.txt +0 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/ethspecify.egg-info/entry_points.txt +0 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/ethspecify.egg-info/top_level.txt +0 -0
- {ethspecify-0.2.1 → ethspecify-0.2.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ethspecify
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A utility for processing Ethereum specification tags.
|
|
5
5
|
Home-page: https://github.com/jtraglia/ethspecify
|
|
6
6
|
Author: Justin Traglia
|
|
@@ -12,6 +12,7 @@ Requires-Python: >=3.6
|
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: requests==2.32.3
|
|
15
|
+
Requires-Dist: PyYAML>=6.0
|
|
15
16
|
Dynamic: author
|
|
16
17
|
Dynamic: author-email
|
|
17
18
|
Dynamic: classifier
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from .core import grep, replace_spec_tags, get_pyspec, get_latest_fork, get_spec_item_history, load_config, run_checks
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def process(args):
|
|
10
|
+
"""Process all spec tags."""
|
|
11
|
+
project_dir = os.path.abspath(os.path.expanduser(args.path))
|
|
12
|
+
if not os.path.isdir(project_dir):
|
|
13
|
+
print(f"Error: The directory {repr(project_dir)} does not exist.")
|
|
14
|
+
return 1
|
|
15
|
+
|
|
16
|
+
# Load config once from the project directory
|
|
17
|
+
config = load_config(project_dir)
|
|
18
|
+
|
|
19
|
+
for f in grep(project_dir, r"<spec\b.*?>", args.exclude):
|
|
20
|
+
print(f"Processing file: {f}")
|
|
21
|
+
replace_spec_tags(f, config)
|
|
22
|
+
|
|
23
|
+
return 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def list_tags(args):
|
|
27
|
+
"""List all available tags with their fork history."""
|
|
28
|
+
preset = getattr(args, 'preset', 'mainnet')
|
|
29
|
+
return _list_tags_with_history(args, preset)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _list_tags_with_history(args, preset):
|
|
33
|
+
"""List all tags with their fork history."""
|
|
34
|
+
try:
|
|
35
|
+
history = get_spec_item_history(preset)
|
|
36
|
+
except ValueError as e:
|
|
37
|
+
print(f"Error: {e}")
|
|
38
|
+
return 1
|
|
39
|
+
|
|
40
|
+
if args.format == "json":
|
|
41
|
+
result = {
|
|
42
|
+
"preset": preset,
|
|
43
|
+
"mode": "history",
|
|
44
|
+
"history": history
|
|
45
|
+
}
|
|
46
|
+
print(json.dumps(result, indent=2))
|
|
47
|
+
else:
|
|
48
|
+
print(f"Available tags across all forks ({preset} preset):")
|
|
49
|
+
|
|
50
|
+
def _print_items_with_history(category_name, items_dict, spec_attr):
|
|
51
|
+
"""Helper to print items with their fork history."""
|
|
52
|
+
if not items_dict:
|
|
53
|
+
return
|
|
54
|
+
print(f"\n{category_name}:")
|
|
55
|
+
for item_name in sorted(items_dict.keys()):
|
|
56
|
+
if args.search is None or args.search.lower() in item_name.lower():
|
|
57
|
+
forks = items_dict[item_name]
|
|
58
|
+
fork_list = ", ".join(forks)
|
|
59
|
+
print(f" <spec {spec_attr}=\"{item_name}\" /> ({fork_list})")
|
|
60
|
+
|
|
61
|
+
_print_items_with_history("Functions", history['functions'], "fn")
|
|
62
|
+
_print_items_with_history("Constants", history['constant_vars'], "constant_var")
|
|
63
|
+
_print_items_with_history("Custom Types", history['custom_types'], "custom_type")
|
|
64
|
+
_print_items_with_history("SSZ Objects", history['ssz_objects'], "ssz_object")
|
|
65
|
+
_print_items_with_history("Dataclasses", history['dataclasses'], "dataclass")
|
|
66
|
+
_print_items_with_history("Preset Variables", history['preset_vars'], "preset_var")
|
|
67
|
+
_print_items_with_history("Config Variables", history['config_vars'], "config_var")
|
|
68
|
+
|
|
69
|
+
return 0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def check(args):
|
|
73
|
+
"""Run checks to validate spec references."""
|
|
74
|
+
project_dir = os.path.abspath(os.path.expanduser(args.path))
|
|
75
|
+
if not os.path.isdir(project_dir):
|
|
76
|
+
print(f"Error: The directory {repr(project_dir)} does not exist.")
|
|
77
|
+
return 1
|
|
78
|
+
|
|
79
|
+
# Load config
|
|
80
|
+
config = load_config(project_dir)
|
|
81
|
+
|
|
82
|
+
# Run checks
|
|
83
|
+
success, results = run_checks(project_dir, config)
|
|
84
|
+
|
|
85
|
+
# Collect all missing items and errors
|
|
86
|
+
all_missing = []
|
|
87
|
+
all_errors = []
|
|
88
|
+
total_coverage = {"found": 0, "expected": 0}
|
|
89
|
+
total_source_files = {"valid": 0, "total": 0}
|
|
90
|
+
|
|
91
|
+
for section_name, section_results in results.items():
|
|
92
|
+
# Determine the type prefix from section name
|
|
93
|
+
if "Config Variables" in section_name:
|
|
94
|
+
type_prefix = "config_var"
|
|
95
|
+
elif "Preset Variables" in section_name:
|
|
96
|
+
type_prefix = "preset_var"
|
|
97
|
+
elif "Ssz Objects" in section_name:
|
|
98
|
+
type_prefix = "ssz_object"
|
|
99
|
+
elif "Dataclasses" in section_name:
|
|
100
|
+
type_prefix = "dataclass"
|
|
101
|
+
else:
|
|
102
|
+
type_prefix = section_name.lower().replace(" ", "_")
|
|
103
|
+
|
|
104
|
+
# Collect source file errors
|
|
105
|
+
source = section_results['source_files']
|
|
106
|
+
total_source_files["valid"] += source["valid"]
|
|
107
|
+
total_source_files["total"] += source["total"]
|
|
108
|
+
all_errors.extend(source["errors"])
|
|
109
|
+
|
|
110
|
+
# Collect missing items with type prefix
|
|
111
|
+
coverage = section_results['coverage']
|
|
112
|
+
total_coverage["found"] += coverage["found"]
|
|
113
|
+
total_coverage["expected"] += coverage["expected"]
|
|
114
|
+
for missing in coverage['missing']:
|
|
115
|
+
all_missing.append(f"MISSING: {type_prefix}.{missing}")
|
|
116
|
+
|
|
117
|
+
# Display only errors and missing items
|
|
118
|
+
for error in all_errors:
|
|
119
|
+
print(error)
|
|
120
|
+
|
|
121
|
+
for missing in sorted(all_missing):
|
|
122
|
+
print(missing)
|
|
123
|
+
|
|
124
|
+
if all_errors or all_missing:
|
|
125
|
+
return 1
|
|
126
|
+
else:
|
|
127
|
+
total_refs = total_coverage['expected']
|
|
128
|
+
print(f"All specification references ({total_refs}) are valid.")
|
|
129
|
+
return 0
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def list_forks(args):
|
|
133
|
+
"""List all available forks."""
|
|
134
|
+
pyspec = get_pyspec()
|
|
135
|
+
preset = args.preset
|
|
136
|
+
|
|
137
|
+
if preset not in pyspec:
|
|
138
|
+
print(f"Error: Preset '{preset}' not found.")
|
|
139
|
+
print(f"Available presets: {', '.join(pyspec.keys())}")
|
|
140
|
+
return 1
|
|
141
|
+
|
|
142
|
+
# Filter out EIP forks
|
|
143
|
+
forks = sorted(
|
|
144
|
+
[fork for fork in pyspec[preset].keys() if not fork.startswith("eip")],
|
|
145
|
+
key=lambda x: (x != "phase0", x)
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if args.format == "json":
|
|
149
|
+
result = {
|
|
150
|
+
"preset": preset,
|
|
151
|
+
"forks": forks
|
|
152
|
+
}
|
|
153
|
+
print(json.dumps(result, indent=2))
|
|
154
|
+
else:
|
|
155
|
+
print(f"Available forks for {preset} preset:")
|
|
156
|
+
for fork in forks:
|
|
157
|
+
print(f" {fork}")
|
|
158
|
+
|
|
159
|
+
return 0
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def main():
|
|
163
|
+
parser = argparse.ArgumentParser(
|
|
164
|
+
description="Process files containing <spec> tags."
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Create subparsers for different commands
|
|
168
|
+
subparsers = parser.add_subparsers(dest="command", help="Command to execute")
|
|
169
|
+
|
|
170
|
+
# Parser for 'process' command
|
|
171
|
+
process_parser = subparsers.add_parser("process", help="Process spec tags in files")
|
|
172
|
+
process_parser.set_defaults(func=process)
|
|
173
|
+
process_parser.add_argument(
|
|
174
|
+
"--path",
|
|
175
|
+
type=str,
|
|
176
|
+
help="Directory to search for files containing <spec> tags",
|
|
177
|
+
default=".",
|
|
178
|
+
)
|
|
179
|
+
process_parser.add_argument(
|
|
180
|
+
"--exclude",
|
|
181
|
+
action="append",
|
|
182
|
+
help="Exclude paths matching this regex",
|
|
183
|
+
default=[],
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Parser for 'list-tags' command
|
|
187
|
+
list_tags_parser = subparsers.add_parser("list-tags", help="List available specification tags with fork history")
|
|
188
|
+
list_tags_parser.set_defaults(func=list_tags)
|
|
189
|
+
list_tags_parser.add_argument(
|
|
190
|
+
"--format",
|
|
191
|
+
type=str,
|
|
192
|
+
choices=["text", "json"],
|
|
193
|
+
default="text",
|
|
194
|
+
help="Output format (text or json)",
|
|
195
|
+
)
|
|
196
|
+
list_tags_parser.add_argument(
|
|
197
|
+
"--search",
|
|
198
|
+
type=str,
|
|
199
|
+
help="Filter tags by search term",
|
|
200
|
+
default=None,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Parser for 'check' command
|
|
204
|
+
check_parser = subparsers.add_parser("check", help="Check spec reference coverage and validity")
|
|
205
|
+
check_parser.set_defaults(func=check)
|
|
206
|
+
check_parser.add_argument(
|
|
207
|
+
"--path",
|
|
208
|
+
type=str,
|
|
209
|
+
help="Directory containing YAML files to check",
|
|
210
|
+
default=".",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Parser for 'list-forks' command
|
|
214
|
+
list_forks_parser = subparsers.add_parser("list-forks", help="List available forks")
|
|
215
|
+
list_forks_parser.set_defaults(func=list_forks)
|
|
216
|
+
list_forks_parser.add_argument(
|
|
217
|
+
"--preset",
|
|
218
|
+
type=str,
|
|
219
|
+
help="Preset to use (mainnet or minimal)",
|
|
220
|
+
default="mainnet",
|
|
221
|
+
)
|
|
222
|
+
list_forks_parser.add_argument(
|
|
223
|
+
"--format",
|
|
224
|
+
type=str,
|
|
225
|
+
choices=["text", "json"],
|
|
226
|
+
default="text",
|
|
227
|
+
help="Output format (text or json)",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Default to 'process' if no args are provided
|
|
231
|
+
if len(sys.argv) == 1:
|
|
232
|
+
sys.argv.insert(1, "process")
|
|
233
|
+
|
|
234
|
+
args = parser.parse_args()
|
|
235
|
+
exit(args.func(args))
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
if __name__ == "__main__":
|
|
239
|
+
main()
|