ethspecify 0.1.4__tar.gz → 0.2.1__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.

@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ethspecify
3
- Version: 0.1.4
3
+ Version: 0.2.1
4
4
  Summary: A utility for processing Ethereum specification tags.
5
5
  Home-page: https://github.com/jtraglia/ethspecify
6
6
  Author: Justin Traglia
@@ -18,6 +18,7 @@ Dynamic: classifier
18
18
  Dynamic: description
19
19
  Dynamic: description-content-type
20
20
  Dynamic: home-page
21
+ Dynamic: license-file
21
22
  Dynamic: requires-dist
22
23
  Dynamic: requires-python
23
24
  Dynamic: summary
@@ -65,6 +66,20 @@ ethspecify
65
66
 
66
67
  ## Specification Options
67
68
 
69
+ ### Version
70
+
71
+ This attribute specifies which version of the consensus specifications to use. Default is `nightly`.
72
+
73
+ - `nightly` (default) - Uses the latest nightly build from the master branch
74
+ - `v1.6.0-alpha.2`, `v1.6.0-alpha.3`, etc. - Uses a specific tagged release version
75
+
76
+ Example:
77
+ ```
78
+ /*
79
+ * <spec fn="apply_deposit" fork="electra" version="v1.6.0-alpha.3" />
80
+ */
81
+ ```
82
+
68
83
  ### Fork
69
84
 
70
85
  This attribute can be any of the [executable
@@ -41,6 +41,20 @@ ethspecify
41
41
 
42
42
  ## Specification Options
43
43
 
44
+ ### Version
45
+
46
+ This attribute specifies which version of the consensus specifications to use. Default is `nightly`.
47
+
48
+ - `nightly` (default) - Uses the latest nightly build from the master branch
49
+ - `v1.6.0-alpha.2`, `v1.6.0-alpha.3`, etc. - Uses a specific tagged release version
50
+
51
+ Example:
52
+ ```
53
+ /*
54
+ * <spec fn="apply_deposit" fork="electra" version="v1.6.0-alpha.3" />
55
+ */
56
+ ```
57
+
44
58
  ### Fork
45
59
 
46
60
  This attribute can be any of the [executable
@@ -0,0 +1,205 @@
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
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
+ for f in grep(project_dir, r"<spec\b.*?>", args.exclude):
17
+ print(f"Processing file: {f}")
18
+ replace_spec_tags(f)
19
+
20
+ return 0
21
+
22
+
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
29
+
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)}")
35
+ return 1
36
+
37
+ # Format output based on requested format
38
+ if args.format == "json":
39
+ result = {
40
+ "fork": fork,
41
+ "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
+ }
51
+ }
52
+ print(json.dumps(result, indent=2))
53
+ 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} />")
92
+
93
+ return 0
94
+
95
+
96
+ def list_forks(args):
97
+ """List all available forks."""
98
+ pyspec = get_pyspec()
99
+ preset = args.preset
100
+
101
+ if preset not in pyspec:
102
+ print(f"Error: Preset '{preset}' not found.")
103
+ print(f"Available presets: {', '.join(pyspec.keys())}")
104
+ return 1
105
+
106
+ 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)
110
+ )
111
+
112
+ if args.format == "json":
113
+ result = {
114
+ "preset": preset,
115
+ "forks": forks
116
+ }
117
+ print(json.dumps(result, indent=2))
118
+ else:
119
+ print(f"Available forks for {preset} preset:")
120
+ for fork in forks:
121
+ print(f" {fork}")
122
+
123
+ return 0
124
+
125
+
126
+ def main():
127
+ parser = argparse.ArgumentParser(
128
+ description="Process files containing <spec> tags."
129
+ )
130
+
131
+ # Create subparsers for different commands
132
+ subparsers = parser.add_subparsers(dest="command", help="Command to execute")
133
+
134
+ # Parser for 'process' command
135
+ process_parser = subparsers.add_parser("process", help="Process spec tags in files")
136
+ process_parser.set_defaults(func=process)
137
+ process_parser.add_argument(
138
+ "--path",
139
+ type=str,
140
+ help="Directory to search for files containing <spec> tags",
141
+ default=".",
142
+ )
143
+ process_parser.add_argument(
144
+ "--exclude",
145
+ action="append",
146
+ help="Exclude paths matching this regex",
147
+ default=[],
148
+ )
149
+
150
+ # Parser for 'list-tags' command
151
+ list_tags_parser = subparsers.add_parser("list-tags", help="List available specification tags")
152
+ 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
+ list_tags_parser.add_argument(
166
+ "--format",
167
+ type=str,
168
+ choices=["text", "json"],
169
+ default="text",
170
+ help="Output format (text or json)",
171
+ )
172
+ list_tags_parser.add_argument(
173
+ "--search",
174
+ type=str,
175
+ help="Filter tags by search term",
176
+ default=None,
177
+ )
178
+
179
+ # Parser for 'list-forks' command
180
+ list_forks_parser = subparsers.add_parser("list-forks", help="List available forks")
181
+ list_forks_parser.set_defaults(func=list_forks)
182
+ list_forks_parser.add_argument(
183
+ "--preset",
184
+ type=str,
185
+ help="Preset to use (mainnet or minimal)",
186
+ default="mainnet",
187
+ )
188
+ list_forks_parser.add_argument(
189
+ "--format",
190
+ type=str,
191
+ choices=["text", "json"],
192
+ default="text",
193
+ help="Output format (text or json)",
194
+ )
195
+
196
+ # Default to 'process' if no args are provided
197
+ if len(sys.argv) == 1:
198
+ sys.argv.insert(1, "process")
199
+
200
+ args = parser.parse_args()
201
+ exit(args.func(args))
202
+
203
+
204
+ if __name__ == "__main__":
205
+ main()
@@ -83,23 +83,23 @@ def diff(a_name, a_content, b_name, b_content):
83
83
 
84
84
 
85
85
  @functools.lru_cache()
86
- def get_links():
87
- url = f"https://raw.githubusercontent.com/jtraglia/ethspecify/main/links.json"
86
+ def get_links(version="nightly"):
87
+ url = f"https://raw.githubusercontent.com/jtraglia/ethspecify/main/pyspec/{version}/links.json"
88
88
  response = requests.get(url)
89
89
  response.raise_for_status()
90
90
  return response.json()
91
91
 
92
92
 
93
93
  @functools.lru_cache()
94
- def get_pyspec():
95
- url = f"https://raw.githubusercontent.com/jtraglia/ethspecify/main/pyspec.json"
94
+ def get_pyspec(version="nightly"):
95
+ url = f"https://raw.githubusercontent.com/jtraglia/ethspecify/main/pyspec/{version}/pyspec.json"
96
96
  response = requests.get(url)
97
97
  response.raise_for_status()
98
98
  return response.json()
99
99
 
100
100
 
101
- def get_previous_forks(fork):
102
- pyspec = get_pyspec()
101
+ def get_previous_forks(fork, version="nightly"):
102
+ pyspec = get_pyspec(version)
103
103
  config_vars = pyspec["mainnet"][fork]["config_vars"]
104
104
  previous_forks = ["phase0"]
105
105
  for key in config_vars.keys():
@@ -111,8 +111,8 @@ def get_previous_forks(fork):
111
111
  return list(reversed(previous_forks))
112
112
 
113
113
 
114
- def get_spec(attributes, preset, fork):
115
- pyspec = get_pyspec()
114
+ def get_spec(attributes, preset, fork, version="nightly"):
115
+ pyspec = get_pyspec(version)
116
116
  spec = None
117
117
  if "function" in attributes or "fn" in attributes:
118
118
  if "function" in attributes and "fn" in attributes:
@@ -197,6 +197,16 @@ def get_spec(attributes, preset, fork):
197
197
  raise Exception("invalid spec tag")
198
198
  return spec
199
199
 
200
+ def get_latest_fork(version="nightly"):
201
+ """A helper function to get the latest non-eip fork."""
202
+ pyspec = get_pyspec(version)
203
+ forks = sorted(
204
+ pyspec["mainnet"].keys(),
205
+ key=lambda x: (x != "phase0", x.startswith("eip"), x)
206
+ )
207
+ for fork in reversed(forks):
208
+ if not fork.startswith("eip"):
209
+ return fork
200
210
 
201
211
  def parse_common_attributes(attributes):
202
212
  try:
@@ -204,36 +214,41 @@ def parse_common_attributes(attributes):
204
214
  except KeyError:
205
215
  preset = "mainnet"
206
216
 
217
+ try:
218
+ version = attributes["version"]
219
+ except KeyError:
220
+ version = "nightly"
221
+
207
222
  try:
208
223
  fork = attributes["fork"]
209
224
  except KeyError:
210
- raise Exception(f"Missing fork attribute")
225
+ fork = get_latest_fork(version)
211
226
 
212
227
  try:
213
228
  style = attributes["style"]
214
229
  except KeyError:
215
230
  style = "hash"
216
231
 
217
- return preset, fork, style
232
+ return preset, fork, style, version
218
233
 
219
234
  def get_spec_item(attributes):
220
- preset, fork, style = parse_common_attributes(attributes)
221
- spec = get_spec(attributes, preset, fork)
235
+ preset, fork, style, version = parse_common_attributes(attributes)
236
+ spec = get_spec(attributes, preset, fork, version)
222
237
 
223
238
  if style == "full" or style == "hash":
224
239
  return spec
225
240
  elif style == "diff":
226
- previous_forks = get_previous_forks(fork)
241
+ previous_forks = get_previous_forks(fork, version)
227
242
 
228
243
  previous_fork = None
229
244
  previous_spec = None
230
245
  for i, _ in enumerate(previous_forks):
231
246
  previous_fork = previous_forks[i]
232
- previous_spec = get_spec(attributes, preset, previous_fork)
247
+ previous_spec = get_spec(attributes, preset, previous_fork, version)
233
248
  if previous_spec != "phase0":
234
249
  try:
235
250
  previous_previous_fork = previous_forks[i+1]
236
- previous_previous_spec = get_spec(attributes, preset, previous_previous_fork)
251
+ previous_previous_spec = get_spec(attributes, preset, previous_previous_fork, version)
237
252
  if previous_previous_spec == previous_spec:
238
253
  continue
239
254
  except KeyError:
@@ -253,7 +268,7 @@ def get_spec_item(attributes):
253
268
  function_name = attributes["function"]
254
269
  else:
255
270
  function_name = attributes["fn"]
256
- for key, value in get_links().items():
271
+ for key, value in get_links(version).items():
257
272
  if fork in key and key.endswith(function_name):
258
273
  return value
259
274
  return "Could not find link"
@@ -312,8 +327,8 @@ def replace_spec_tags(file_path):
312
327
 
313
328
  attributes = extract_attributes(original_tag_text)
314
329
  print(f"spec tag: {attributes}")
315
- preset, fork, style = parse_common_attributes(attributes)
316
- spec = get_spec(attributes, preset, fork)
330
+ preset, fork, style, version = parse_common_attributes(attributes)
331
+ spec = get_spec(attributes, preset, fork, version)
317
332
  hash_value = hashlib.sha256(spec.encode('utf-8')).hexdigest()[:8]
318
333
 
319
334
  if style == "hash":
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ethspecify
3
- Version: 0.1.4
3
+ Version: 0.2.1
4
4
  Summary: A utility for processing Ethereum specification tags.
5
5
  Home-page: https://github.com/jtraglia/ethspecify
6
6
  Author: Justin Traglia
@@ -18,6 +18,7 @@ Dynamic: classifier
18
18
  Dynamic: description
19
19
  Dynamic: description-content-type
20
20
  Dynamic: home-page
21
+ Dynamic: license-file
21
22
  Dynamic: requires-dist
22
23
  Dynamic: requires-python
23
24
  Dynamic: summary
@@ -65,6 +66,20 @@ ethspecify
65
66
 
66
67
  ## Specification Options
67
68
 
69
+ ### Version
70
+
71
+ This attribute specifies which version of the consensus specifications to use. Default is `nightly`.
72
+
73
+ - `nightly` (default) - Uses the latest nightly build from the master branch
74
+ - `v1.6.0-alpha.2`, `v1.6.0-alpha.3`, etc. - Uses a specific tagged release version
75
+
76
+ Example:
77
+ ```
78
+ /*
79
+ * <spec fn="apply_deposit" fork="electra" version="v1.6.0-alpha.3" />
80
+ */
81
+ ```
82
+
68
83
  ### Fork
69
84
 
70
85
  This attribute can be any of the [executable
@@ -8,7 +8,7 @@ long_description = (this_directory / "README.md").read_text(encoding="utf-8")
8
8
 
9
9
  setup(
10
10
  name="ethspecify",
11
- version="0.1.4",
11
+ version="0.2.1",
12
12
  description="A utility for processing Ethereum specification tags.",
13
13
  long_description=long_description,
14
14
  long_description_content_type="text/markdown",
@@ -30,4 +30,4 @@ setup(
30
30
  "Operating System :: OS Independent",
31
31
  ],
32
32
  python_requires='>=3.6',
33
- )
33
+ )
@@ -1,34 +0,0 @@
1
- import argparse
2
- import os
3
-
4
- from .core import grep, replace_spec_tags
5
-
6
- def main():
7
- parser = argparse.ArgumentParser(
8
- description="Process files containing <spec> tags."
9
- )
10
- parser.add_argument(
11
- "--path",
12
- type=str,
13
- help="Directory to search for files containing <spec> tags",
14
- default=".",
15
- )
16
- parser.add_argument(
17
- "--exclude",
18
- action="append",
19
- help="Exclude paths matching this regex",
20
- default=[],
21
- )
22
- args = parser.parse_args()
23
-
24
- project_dir = os.path.abspath(os.path.expanduser(args.path))
25
- if not os.path.isdir(project_dir):
26
- print(f"Error: The directory '{project_dir}' does not exist.")
27
- exit(1)
28
-
29
- for f in grep(project_dir, r"<spec\b.*?>", args.exclude):
30
- print(f"Processing file: {f}")
31
- replace_spec_tags(f)
32
-
33
- if __name__ == "__main__":
34
- main()
File without changes
File without changes