ethspecify 0.2.4__tar.gz → 0.2.6__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.
- {ethspecify-0.2.4 → ethspecify-0.2.6}/PKG-INFO +1 -1
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify/cli.py +21 -15
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify/core.py +256 -9
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify.egg-info/PKG-INFO +1 -1
- {ethspecify-0.2.4 → ethspecify-0.2.6}/setup.py +1 -1
- {ethspecify-0.2.4 → ethspecify-0.2.6}/LICENSE +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/README.md +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify/__init__.py +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify.egg-info/SOURCES.txt +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify.egg-info/dependency_links.txt +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify.egg-info/entry_points.txt +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify.egg-info/requires.txt +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/ethspecify.egg-info/top_level.txt +0 -0
- {ethspecify-0.2.4 → ethspecify-0.2.6}/setup.cfg +0 -0
|
@@ -89,30 +89,36 @@ def check(args):
|
|
|
89
89
|
total_source_files = {"valid": 0, "total": 0}
|
|
90
90
|
|
|
91
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
92
|
# Collect source file errors
|
|
105
93
|
source = section_results['source_files']
|
|
106
94
|
total_source_files["valid"] += source["valid"]
|
|
107
95
|
total_source_files["total"] += source["total"]
|
|
108
96
|
all_errors.extend(source["errors"])
|
|
109
97
|
|
|
110
|
-
# Collect missing items
|
|
98
|
+
# Collect missing items
|
|
111
99
|
coverage = section_results['coverage']
|
|
112
100
|
total_coverage["found"] += coverage["found"]
|
|
113
101
|
total_coverage["expected"] += coverage["expected"]
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
|
|
103
|
+
# For Project Coverage, items already have the proper prefix
|
|
104
|
+
if section_name == "Project Coverage":
|
|
105
|
+
for missing in coverage['missing']:
|
|
106
|
+
all_missing.append(f"MISSING: {missing}")
|
|
107
|
+
else:
|
|
108
|
+
# Determine the type prefix from section name for YAML-based checks
|
|
109
|
+
if "Config Variables" in section_name:
|
|
110
|
+
type_prefix = "config_var"
|
|
111
|
+
elif "Preset Variables" in section_name:
|
|
112
|
+
type_prefix = "preset_var"
|
|
113
|
+
elif "Ssz Objects" in section_name:
|
|
114
|
+
type_prefix = "ssz_object"
|
|
115
|
+
elif "Dataclasses" in section_name:
|
|
116
|
+
type_prefix = "dataclass"
|
|
117
|
+
else:
|
|
118
|
+
type_prefix = section_name.lower().replace(" ", "_")
|
|
119
|
+
|
|
120
|
+
for missing in coverage['missing']:
|
|
121
|
+
all_missing.append(f"MISSING: {type_prefix}.{missing}")
|
|
116
122
|
|
|
117
123
|
# Display only errors and missing items
|
|
118
124
|
for error in all_errors:
|
|
@@ -822,7 +822,197 @@ def extract_spec_tags_from_yaml(yaml_file, tag_type=None):
|
|
|
822
822
|
return tag_types_found, pairs
|
|
823
823
|
|
|
824
824
|
|
|
825
|
-
def
|
|
825
|
+
def generate_specrefs_from_files(files_with_spec_tags, project_dir):
|
|
826
|
+
"""
|
|
827
|
+
Generate specrefs data from files containing spec tags.
|
|
828
|
+
Returns a dict with spec tag info and their source locations.
|
|
829
|
+
"""
|
|
830
|
+
specrefs = {}
|
|
831
|
+
|
|
832
|
+
for file_path in files_with_spec_tags:
|
|
833
|
+
try:
|
|
834
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
835
|
+
content = f.read()
|
|
836
|
+
|
|
837
|
+
# Find all spec tags in the file
|
|
838
|
+
spec_tag_pattern = r'<spec\s+([^>]+?)(?:\s*/>|>)'
|
|
839
|
+
matches = re.finditer(spec_tag_pattern, content)
|
|
840
|
+
|
|
841
|
+
for match in matches:
|
|
842
|
+
tag_attrs_str = match.group(1)
|
|
843
|
+
attrs = extract_attributes(f"<spec {tag_attrs_str}>")
|
|
844
|
+
|
|
845
|
+
# Determine the spec type and name
|
|
846
|
+
spec_type = None
|
|
847
|
+
spec_name = None
|
|
848
|
+
fork = attrs.get('fork', None)
|
|
849
|
+
|
|
850
|
+
# Check each possible spec attribute
|
|
851
|
+
for attr_name in ['fn', 'function', 'constant_var', 'config_var',
|
|
852
|
+
'preset_var', 'ssz_object', 'dataclass', 'custom_type']:
|
|
853
|
+
if attr_name in attrs:
|
|
854
|
+
spec_type = attr_name
|
|
855
|
+
spec_name = attrs[attr_name]
|
|
856
|
+
break
|
|
857
|
+
|
|
858
|
+
if spec_type and spec_name:
|
|
859
|
+
# Create a unique key for this spec reference
|
|
860
|
+
key = f"{spec_type}.{spec_name}"
|
|
861
|
+
if fork:
|
|
862
|
+
key += f"#{fork}"
|
|
863
|
+
|
|
864
|
+
if key not in specrefs:
|
|
865
|
+
specrefs[key] = {
|
|
866
|
+
'name': spec_name,
|
|
867
|
+
'type': spec_type,
|
|
868
|
+
'fork': fork,
|
|
869
|
+
'sources': []
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
# Add this source location
|
|
873
|
+
rel_path = os.path.relpath(file_path, project_dir)
|
|
874
|
+
|
|
875
|
+
# Get line number of the match
|
|
876
|
+
lines_before = content[:match.start()].count('\n')
|
|
877
|
+
line_num = lines_before + 1
|
|
878
|
+
|
|
879
|
+
specrefs[key]['sources'].append({
|
|
880
|
+
'file': rel_path,
|
|
881
|
+
'line': line_num
|
|
882
|
+
})
|
|
883
|
+
|
|
884
|
+
except (IOError, UnicodeDecodeError):
|
|
885
|
+
continue
|
|
886
|
+
|
|
887
|
+
return specrefs
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
def process_generated_specrefs(specrefs, exceptions, version):
|
|
891
|
+
"""
|
|
892
|
+
Process the generated specrefs and check coverage.
|
|
893
|
+
Returns (success, results)
|
|
894
|
+
"""
|
|
895
|
+
results = {}
|
|
896
|
+
overall_success = True
|
|
897
|
+
|
|
898
|
+
# Group specrefs by type for coverage checking
|
|
899
|
+
specrefs_by_type = {}
|
|
900
|
+
for _, data in specrefs.items():
|
|
901
|
+
spec_type = data['type']
|
|
902
|
+
if spec_type not in specrefs_by_type:
|
|
903
|
+
specrefs_by_type[spec_type] = []
|
|
904
|
+
specrefs_by_type[spec_type].append(data)
|
|
905
|
+
|
|
906
|
+
# Map spec types to history keys
|
|
907
|
+
type_to_history_key = {
|
|
908
|
+
'fn': 'functions',
|
|
909
|
+
'function': 'functions',
|
|
910
|
+
'constant_var': 'constant_vars',
|
|
911
|
+
'config_var': 'config_vars',
|
|
912
|
+
'preset_var': 'preset_vars',
|
|
913
|
+
'ssz_object': 'ssz_objects',
|
|
914
|
+
'dataclass': 'dataclasses',
|
|
915
|
+
'custom_type': 'custom_types'
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
# Map to exception keys
|
|
919
|
+
type_to_exception_key = {
|
|
920
|
+
'fn': 'functions',
|
|
921
|
+
'function': 'functions',
|
|
922
|
+
'constant_var': 'constants',
|
|
923
|
+
'config_var': 'configs',
|
|
924
|
+
'preset_var': 'presets',
|
|
925
|
+
'ssz_object': 'ssz_objects',
|
|
926
|
+
'dataclass': 'dataclasses',
|
|
927
|
+
'custom_type': 'custom_types'
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
# Get spec history for coverage checking
|
|
931
|
+
history = get_spec_item_history("mainnet", version)
|
|
932
|
+
|
|
933
|
+
# Check coverage for each type
|
|
934
|
+
total_found = 0
|
|
935
|
+
total_expected = 0
|
|
936
|
+
all_missing = []
|
|
937
|
+
|
|
938
|
+
for spec_type, items in specrefs_by_type.items():
|
|
939
|
+
history_key = type_to_history_key.get(spec_type, spec_type)
|
|
940
|
+
exception_key = type_to_exception_key.get(spec_type, spec_type)
|
|
941
|
+
|
|
942
|
+
# Get exceptions for this type - handle both singular and plural keys
|
|
943
|
+
type_exceptions = []
|
|
944
|
+
if exception_key in exceptions:
|
|
945
|
+
type_exceptions = exceptions[exception_key]
|
|
946
|
+
# Also check plural forms
|
|
947
|
+
elif exception_key + 's' in exceptions:
|
|
948
|
+
type_exceptions = exceptions[exception_key + 's']
|
|
949
|
+
# Check if singular form exists when we have plural
|
|
950
|
+
elif exception_key.endswith('s') and exception_key[:-1] in exceptions:
|
|
951
|
+
type_exceptions = exceptions[exception_key[:-1]]
|
|
952
|
+
|
|
953
|
+
# Build set of what we found
|
|
954
|
+
found_items = set()
|
|
955
|
+
for item in items:
|
|
956
|
+
if item['fork']:
|
|
957
|
+
found_items.add(f"{item['name']}#{item['fork']}")
|
|
958
|
+
else:
|
|
959
|
+
# If no fork specified, we need to check all forks
|
|
960
|
+
if history_key in history and item['name'] in history[history_key]:
|
|
961
|
+
for fork in history[history_key][item['name']]:
|
|
962
|
+
found_items.add(f"{item['name']}#{fork}")
|
|
963
|
+
|
|
964
|
+
# Check what's expected
|
|
965
|
+
if history_key in history:
|
|
966
|
+
for item_name, forks in history[history_key].items():
|
|
967
|
+
for fork in forks:
|
|
968
|
+
expected_key = f"{item_name}#{fork}"
|
|
969
|
+
total_expected += 1
|
|
970
|
+
|
|
971
|
+
# Check if excepted
|
|
972
|
+
if is_excepted(item_name, fork, type_exceptions):
|
|
973
|
+
total_found += 1
|
|
974
|
+
continue
|
|
975
|
+
|
|
976
|
+
if expected_key in found_items:
|
|
977
|
+
total_found += 1
|
|
978
|
+
else:
|
|
979
|
+
# Use the proper type prefix for the missing item
|
|
980
|
+
type_prefix_map = {
|
|
981
|
+
'functions': 'functions',
|
|
982
|
+
'constant_vars': 'constants',
|
|
983
|
+
'config_vars': 'configs',
|
|
984
|
+
'preset_vars': 'presets',
|
|
985
|
+
'ssz_objects': 'ssz_objects',
|
|
986
|
+
'dataclasses': 'dataclasses',
|
|
987
|
+
'custom_types': 'custom_types'
|
|
988
|
+
}
|
|
989
|
+
prefix = type_prefix_map.get(history_key, history_key)
|
|
990
|
+
all_missing.append(f"{prefix}.{expected_key}")
|
|
991
|
+
|
|
992
|
+
# Count total spec references found
|
|
993
|
+
total_refs = len(specrefs)
|
|
994
|
+
|
|
995
|
+
# Store results
|
|
996
|
+
results['Project Coverage'] = {
|
|
997
|
+
'source_files': {
|
|
998
|
+
'valid': total_refs,
|
|
999
|
+
'total': total_refs,
|
|
1000
|
+
'errors': []
|
|
1001
|
+
},
|
|
1002
|
+
'coverage': {
|
|
1003
|
+
'found': total_found,
|
|
1004
|
+
'expected': total_expected,
|
|
1005
|
+
'missing': all_missing
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
if all_missing:
|
|
1010
|
+
overall_success = False
|
|
1011
|
+
|
|
1012
|
+
return overall_success, results
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
def check_coverage(yaml_file, tag_type, exceptions, preset="mainnet", version="nightly"):
|
|
826
1016
|
"""
|
|
827
1017
|
Check that all spec items from ethspecify have corresponding tags in the YAML file.
|
|
828
1018
|
Returns (found_count, total_count, missing_items)
|
|
@@ -839,7 +1029,7 @@ def check_coverage(yaml_file, tag_type, exceptions, preset="mainnet"):
|
|
|
839
1029
|
}
|
|
840
1030
|
|
|
841
1031
|
# Get expected items from ethspecify
|
|
842
|
-
history = get_spec_item_history(preset)
|
|
1032
|
+
history = get_spec_item_history(preset, version)
|
|
843
1033
|
expected_pairs = set()
|
|
844
1034
|
|
|
845
1035
|
history_key = history_key_map.get(tag_type, tag_type)
|
|
@@ -876,6 +1066,9 @@ def run_checks(project_dir, config):
|
|
|
876
1066
|
results = {}
|
|
877
1067
|
overall_success = True
|
|
878
1068
|
|
|
1069
|
+
# Get version from config
|
|
1070
|
+
version = config.get('version', 'nightly')
|
|
1071
|
+
|
|
879
1072
|
# Get specrefs config
|
|
880
1073
|
specrefs_config = config.get('specrefs', {})
|
|
881
1074
|
|
|
@@ -887,12 +1080,48 @@ def run_checks(project_dir, config):
|
|
|
887
1080
|
else:
|
|
888
1081
|
# New format: specrefs: { files: [...], exceptions: {...} }
|
|
889
1082
|
specrefs_files = specrefs_config.get('files', [])
|
|
890
|
-
exceptions = specrefs_config.get('exceptions', {})
|
|
891
1083
|
|
|
1084
|
+
# Support exceptions in either specrefs section or root, but not both
|
|
1085
|
+
specrefs_exceptions = specrefs_config.get('exceptions', {})
|
|
1086
|
+
root_exceptions = config.get('exceptions', {})
|
|
1087
|
+
|
|
1088
|
+
if specrefs_exceptions and root_exceptions:
|
|
1089
|
+
print("Warning: Exceptions found in both root and specrefs sections. Using specrefs exceptions.")
|
|
1090
|
+
exceptions = specrefs_exceptions
|
|
1091
|
+
elif specrefs_exceptions:
|
|
1092
|
+
exceptions = specrefs_exceptions
|
|
1093
|
+
else:
|
|
1094
|
+
exceptions = root_exceptions
|
|
1095
|
+
|
|
1096
|
+
# If no files specified, search the whole project for spec tags
|
|
892
1097
|
if not specrefs_files:
|
|
893
|
-
print("
|
|
894
|
-
|
|
895
|
-
|
|
1098
|
+
print("No specific files configured, searching entire project for spec tags...")
|
|
1099
|
+
|
|
1100
|
+
# Determine search root - configurable in specrefs section
|
|
1101
|
+
if 'search_root' in specrefs_config:
|
|
1102
|
+
# Use configured search_root (relative to project_dir)
|
|
1103
|
+
search_root_rel = specrefs_config['search_root']
|
|
1104
|
+
search_root = os.path.join(project_dir, search_root_rel) if not os.path.isabs(search_root_rel) else search_root_rel
|
|
1105
|
+
search_root = os.path.abspath(search_root)
|
|
1106
|
+
else:
|
|
1107
|
+
# Default behavior: if we're in a specrefs directory, search in the parent directory
|
|
1108
|
+
search_root = os.path.dirname(project_dir) if os.path.basename(project_dir) == 'specrefs' else project_dir
|
|
1109
|
+
|
|
1110
|
+
print(f"Searching for spec tags in: {search_root}")
|
|
1111
|
+
|
|
1112
|
+
# Use grep to find all files containing spec tags
|
|
1113
|
+
files_with_spec_tags = grep(search_root, r'<spec\b[^>]*>', [])
|
|
1114
|
+
|
|
1115
|
+
if not files_with_spec_tags:
|
|
1116
|
+
print(f"No files with spec tags found in the project")
|
|
1117
|
+
return True, {}
|
|
1118
|
+
|
|
1119
|
+
# Generate in-memory specrefs data from the found spec tags
|
|
1120
|
+
all_specrefs = generate_specrefs_from_files(files_with_spec_tags, search_root)
|
|
1121
|
+
|
|
1122
|
+
# Process the generated specrefs
|
|
1123
|
+
return process_generated_specrefs(all_specrefs, exceptions, version)
|
|
1124
|
+
|
|
896
1125
|
|
|
897
1126
|
# Map tag types to exception keys (support both singular and plural)
|
|
898
1127
|
exception_key_map = {
|
|
@@ -925,7 +1154,16 @@ def run_checks(project_dir, config):
|
|
|
925
1154
|
# Process each tag type found in the file
|
|
926
1155
|
if not tag_types_found:
|
|
927
1156
|
# No spec tags found, still check source files
|
|
928
|
-
|
|
1157
|
+
# Determine source root - use search_root if configured, otherwise use default behavior
|
|
1158
|
+
if 'search_root' in specrefs_config:
|
|
1159
|
+
search_root_rel = specrefs_config['search_root']
|
|
1160
|
+
source_root = os.path.join(project_dir, search_root_rel) if not os.path.isabs(search_root_rel) else search_root_rel
|
|
1161
|
+
source_root = os.path.abspath(source_root)
|
|
1162
|
+
else:
|
|
1163
|
+
# Default behavior: parent directory
|
|
1164
|
+
source_root = os.path.dirname(project_dir)
|
|
1165
|
+
|
|
1166
|
+
valid_count, total_count, source_errors = check_source_files(yaml_path, source_root, [])
|
|
929
1167
|
|
|
930
1168
|
# Store results using filename as section name
|
|
931
1169
|
section_name = filename.replace('.yml', '').replace('-', ' ').title()
|
|
@@ -963,7 +1201,7 @@ def run_checks(project_dir, config):
|
|
|
963
1201
|
break
|
|
964
1202
|
|
|
965
1203
|
# Check coverage for this specific tag type
|
|
966
|
-
found_count, expected_count, missing_items = check_coverage(yaml_path, tag_type, section_exceptions, preset)
|
|
1204
|
+
found_count, expected_count, missing_items = check_coverage(yaml_path, tag_type, section_exceptions, preset, version)
|
|
967
1205
|
total_found += found_count
|
|
968
1206
|
total_expected += expected_count
|
|
969
1207
|
all_missing_items.extend(missing_items)
|
|
@@ -977,7 +1215,16 @@ def run_checks(project_dir, config):
|
|
|
977
1215
|
if key in exceptions:
|
|
978
1216
|
all_exceptions.extend(exceptions[key])
|
|
979
1217
|
|
|
980
|
-
|
|
1218
|
+
# Determine source root - use search_root if configured, otherwise use default behavior
|
|
1219
|
+
if 'search_root' in specrefs_config:
|
|
1220
|
+
search_root_rel = specrefs_config['search_root']
|
|
1221
|
+
source_root = os.path.join(project_dir, search_root_rel) if not os.path.isabs(search_root_rel) else search_root_rel
|
|
1222
|
+
source_root = os.path.abspath(source_root)
|
|
1223
|
+
else:
|
|
1224
|
+
# Default behavior: parent directory
|
|
1225
|
+
source_root = os.path.dirname(project_dir)
|
|
1226
|
+
|
|
1227
|
+
valid_count, total_count, source_errors = check_source_files(yaml_path, source_root, all_exceptions)
|
|
981
1228
|
|
|
982
1229
|
# Store results using filename as section name
|
|
983
1230
|
section_name = filename.replace('.yml', '').replace('-', ' ').title()
|
|
@@ -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.2.
|
|
11
|
+
version="0.2.6",
|
|
12
12
|
description="A utility for processing Ethereum specification tags.",
|
|
13
13
|
long_description=long_description,
|
|
14
14
|
long_description_content_type="text/markdown",
|
|
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
|