Skip to content

Commit a369f7e

Browse files
committed
Run black on python files with 120 char line length
1 parent 1adb09b commit a369f7e

5 files changed

Lines changed: 211 additions & 151 deletions

File tree

scripts/calculate_hashes.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# Output file
1010
output_file = "hashes.json"
1111

12+
1213
# Function to compute SHA256 hash of a file
1314
def compute_hash(file_path):
1415
sha256 = hashlib.sha256()
@@ -17,23 +18,24 @@ def compute_hash(file_path):
1718
sha256.update(chunk)
1819
return sha256.hexdigest()
1920

21+
2022
# Collect hashes
2123
hashes = {}
2224
for root, dirs, files in os.walk(directory):
2325
for file in files:
2426
if file.endswith((".json", ".yaml", ".yml")):
2527
file_path = os.path.join(root, file)
2628
relative_path = os.path.relpath(file_path, directory)
27-
timestamp = ''
29+
timestamp = ""
2830
if file.endswith(".json"):
2931
with open(file, "r") as f:
3032
data = json.load(f)
3133
timestamp = data["timestamp"]
32-
elif file.endswith(( ".yaml", ".yml")):
34+
elif file.endswith((".yaml", ".yml")):
3335
with open(file, "r") as f:
3436
data = yaml.load(f, Loader=yaml.FullLoader)
3537
timestamp = data["timestamp"]
36-
hashes[relative_path] = {'hash': compute_hash(file_path), 'timestamp': timestamp}
38+
hashes[relative_path] = {"hash": compute_hash(file_path), "timestamp": timestamp}
3739

3840
# Write hashes to JSON file
3941
with open(output_file, "w") as f:

scripts/generate_data_files.py

Lines changed: 71 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,20 @@
2020
EESSI_REFERENCE_ARCHITECTURE = "x86_64/intel/icelake"
2121

2222
# Give order to my toolchains so I can easily figure out what "latest" means
23-
EESSI_SUPPORTED_TOP_LEVEL_TOOLCHAINS = OrderedDict({
24-
'2025.06': [
25-
{'name': 'foss', 'version': '2025a'},
26-
{'name': 'foss', 'version': '2024a'},
27-
],
28-
'2023.06': [
29-
{'name': 'foss', 'version': '2023b'},
30-
{'name': 'foss', 'version': '2023a'},
31-
{'name': 'foss', 'version': '2022b'},
32-
],
33-
})
23+
EESSI_SUPPORTED_TOP_LEVEL_TOOLCHAINS = OrderedDict(
24+
{
25+
"2025.06": [
26+
{"name": "foss", "version": "2025a"},
27+
{"name": "foss", "version": "2024a"},
28+
],
29+
"2023.06": [
30+
{"name": "foss", "version": "2023b"},
31+
{"name": "foss", "version": "2023a"},
32+
{"name": "foss", "version": "2022b"},
33+
],
34+
}
35+
)
36+
3437

3538
@contextmanager
3639
def suppress_stdout():
@@ -56,26 +59,17 @@ def load_and_list_modules(module_name):
5659
module --terse list 2>&1
5760
"""
5861

59-
result = subprocess.run(
60-
["bash", "-c", cmd],
61-
stdout=subprocess.PIPE,
62-
stderr=subprocess.STDOUT,
63-
text=True
64-
)
62+
result = subprocess.run(["bash", "-c", cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
6563

6664
if result.returncode != 0:
6765
raise RuntimeError(f"Failed to load module '{module_name}':\n{result.stdout}")
6866

6967
# Parse module list output
70-
modules = [
71-
line
72-
for line in result.stdout.splitlines()
73-
if "/" in line
74-
]
75-
68+
modules = [line for line in result.stdout.splitlines() if "/" in line]
69+
7670
# Filter out the modules we expect to be loaded
77-
eessi_extend_module_stub = 'EESSI-extend/'
78-
eb_module_stub = 'EasyBuild/'
71+
eessi_extend_module_stub = "EESSI-extend/"
72+
eb_module_stub = "EasyBuild/"
7973
if module_name.startswith(eessi_extend_module_stub):
8074
# Don't filter anything
8175
pass
@@ -84,7 +78,11 @@ def load_and_list_modules(module_name):
8478
modules = [module for module in modules if not module.startswith(eessi_extend_module_stub)]
8579
else:
8680
# Filter EESSI-extend and EasyBuild
87-
modules = [module for module in modules if not module.startswith(eessi_extend_module_stub) and not module.startswith(eb_module_stub)]
81+
modules = [
82+
module
83+
for module in modules
84+
if not module.startswith(eessi_extend_module_stub) and not module.startswith(eb_module_stub)
85+
]
8886

8987
return modules
9088

@@ -96,23 +94,23 @@ def use_timestamped_reprod_if_exists(original_path):
9694
"""
9795
# Default to returning the original path
9896
returned_path = original_path
99-
97+
10098
# Split path
10199
parts = original_path.strip(os.sep).split(os.sep)
102100

103101
# Find the last occurrence of 'software'
104-
idx = len(parts) - 1 - parts[::-1].index('software')
102+
idx = len(parts) - 1 - parts[::-1].index("software")
105103

106104
# Replace 'software' by 'reprod'
107-
parts[idx] = 'reprod'
105+
parts[idx] = "reprod"
108106

109107
# Path up to version directory (software/software/version)
110-
pre_timestamp = os.sep.join([''] + parts[:idx+3])
108+
pre_timestamp = os.sep.join([""] + parts[: idx + 3])
111109
# Path after version directory (easybuild/reprod/easyblocks)
112-
post_version = parts[idx+3:]
110+
post_version = parts[idx + 3 :]
113111

114112
# Look for timestamp directories under pre_timestamp
115-
timestamp_dirs = [d for d in glob.glob(os.path.join(pre_timestamp, '*')) if os.path.isdir(d)]
113+
timestamp_dirs = [d for d in glob.glob(os.path.join(pre_timestamp, "*")) if os.path.isdir(d)]
116114
if timestamp_dirs:
117115
latest_timestamp = max(timestamp_dirs) # lexicographic order
118116
# Reconstruct path: reprod/.../version/<latest_timestamp>/easybuild/reprod/easyblocks
@@ -122,48 +120,49 @@ def use_timestamped_reprod_if_exists(original_path):
122120

123121
return returned_path
124122

123+
125124
def collect_eb_files(base_path):
126125
"""
127126
Scan for .eb files and their corresponding *-easybuild-devel files,
128127
extract the major EasyBuild version from devel files, and group .eb files by major version.
129128
For folders containing 'EasyBuild' or 'EESSI-extend', assume the loaded EasyBuild version if extraction fails.
130-
129+
131130
Parameters:
132131
base_path (str): Root folder to scan for .eb files.
133132
134133
Returns:
135134
dict: {major_version: [list of .eb file paths]}
136135
"""
137136
eb_files_by_version = defaultdict(list)
138-
version_pattern = re.compile(r'software/EasyBuild/(\d+)\.(\d+)\.(\d+)/bin')
137+
version_pattern = re.compile(r"software/EasyBuild/(\d+)\.(\d+)\.(\d+)/bin")
139138

140139
# Get major version from loaded EasyBuild installation for exceptions
141140
easybuild_major_version = str(EASYBUILD_VERSION.version[0])
142141

143142
# Find all .eb files recursively
144-
eb_files = glob.glob(os.path.join(base_path, '*/*/easybuild/*.eb'))
143+
eb_files = glob.glob(os.path.join(base_path, "*/*/easybuild/*.eb"))
145144

146145
for eb_file in eb_files:
147146
folder = os.path.dirname(eb_file)
148147

149148
# Look for the -easybuild-devel file in the same folder
150-
devel_files = glob.glob(os.path.join(folder, '*-easybuild-devel'))
149+
devel_files = glob.glob(os.path.join(folder, "*-easybuild-devel"))
151150
if not devel_files:
152151
raise FileNotFoundError(f"No *-easybuild-devel file found in folder: {folder}")
153152

154153
# Pick the latest devel file if multiple exist
155154
latest_devel = max(devel_files, key=os.path.getmtime)
156155

157156
# Extract the EasyBuild version
158-
with open(latest_devel, 'r') as f:
157+
with open(latest_devel, "r") as f:
159158
content = f.read()
160159
match = version_pattern.search(content)
161160

162161
# Handle exception folders
163-
if 'EasyBuild' in folder or 'EESSI-extend' in folder:
162+
if "EasyBuild" in folder or "EESSI-extend" in folder:
164163
major_version = match.group(1) if match else easybuild_major_version
165164
# Don't add EESSI-extend to EB4 or the same file will appear twice
166-
if 'EESSI-extend' in folder and major_version == '4':
165+
if "EESSI-extend" in folder and major_version == "4":
167166
continue
168167
else:
169168
if not match:
@@ -183,7 +182,7 @@ def collect_eb_files(base_path):
183182
"-e",
184183
required=True,
185184
choices=VALID_EESSI_VERSIONS,
186-
help=f"Allowed versions: {', '.join(VALID_EESSI_VERSIONS)}"
185+
help=f"Allowed versions: {', '.join(VALID_EESSI_VERSIONS)}",
187186
)
188187

189188
args = parser.parse_args()
@@ -192,7 +191,9 @@ def collect_eb_files(base_path):
192191
print(f"Using EESSI version: {eessi_version}")
193192

194193
# We use a single architecture path to gather information about the software versions
195-
base_path = f'/cvmfs/software.eessi.io/versions/{eessi_version}/software/linux/{EESSI_REFERENCE_ARCHITECTURE}/software/'
194+
base_path = (
195+
f"/cvmfs/software.eessi.io/versions/{eessi_version}/software/linux/{EESSI_REFERENCE_ARCHITECTURE}/software/"
196+
)
196197
result = collect_eb_files(base_path)
197198

198199
set_up_configuration(args="")
@@ -203,56 +204,66 @@ def collect_eb_files(base_path):
203204
eessi_software["eessi_version"][eessi_version] = {}
204205
# Add a timestamp
205206
eessi_software["timestamp"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
206-
207+
207208
# Store the toolchain hierarchies supported by the EESSI version
208209
eessi_software["eessi_version"][eessi_version]["toolchain_hierarchy"] = {}
209210
for top_level_toolchain in EESSI_SUPPORTED_TOP_LEVEL_TOOLCHAINS[eessi_version]:
210211
toolchain_family = f"{top_level_toolchain['name']}_{top_level_toolchain['version']}"
211212
# Get the hierarchy and always add the system toolchain
212-
eessi_software["eessi_version"][eessi_version]["toolchain_hierarchy"][toolchain_family] = [{'name': 'system', 'version': 'system'}] + get_toolchain_hierarchy(top_level_toolchain)
213-
213+
eessi_software["eessi_version"][eessi_version]["toolchain_hierarchy"][toolchain_family] = [
214+
{"name": "system", "version": "system"}
215+
] + get_toolchain_hierarchy(top_level_toolchain)
216+
214217
for eb_version_of_install, files in sorted(result.items()):
215218
print(f"Major version {eb_version_of_install}:")
216219
if eb_version_of_install == str(EASYBUILD_VERSION.version[0]):
217220
total_files = len(files)
218221
for i, file in enumerate(files, start=1):
219222
percent = (i / total_files) * 100
220223
print(f"{percent:.1f}% - {file}")
221-
224+
222225
# Don't try to parse an EasyBuild easyconfig that is not the same major release
223-
if '/software/EasyBuild/' in file and f'/EasyBuild/{eb_version_of_install}' not in file:
226+
if "/software/EasyBuild/" in file and f"/EasyBuild/{eb_version_of_install}" not in file:
224227
continue
225228
# print(process_easyconfig(path)[0]['ec'].asdict())
226-
229+
227230
eb_hooks_path = use_timestamped_reprod_if_exists(f"{os.path.dirname(file)}/reprod/easyblocks")
228-
easyblocks_dir = include_easyblocks(tmpdir, [eb_hooks_path+"/*.py"])
231+
easyblocks_dir = include_easyblocks(tmpdir, [eb_hooks_path + "/*.py"])
229232
with suppress_stdout():
230-
parsed_ec=process_easyconfig(file)[0]
233+
parsed_ec = process_easyconfig(file)[0]
231234
# included easyblocks are the first entry in sys.path, so just pop them but keep a list of what was used
232235
sys.path.pop(0)
233-
easyblocks_used = [os.path.basename(f) for f in glob.glob(f"{easyblocks_dir}/**/*.py", recursive=True) if os.path.basename(f) != '__init__.py']
236+
easyblocks_used = [
237+
os.path.basename(f)
238+
for f in glob.glob(f"{easyblocks_dir}/**/*.py", recursive=True)
239+
if os.path.basename(f) != "__init__.py"
240+
]
234241
shutil.rmtree(easyblocks_dir)
235-
242+
236243
# Use the path as the key since we know it is unique
237-
eessi_software["eessi_version"][eessi_version][file] = parsed_ec['ec'].asdict()
238-
eessi_software["eessi_version"][eessi_version][file]['mtime'] = os.path.getmtime(file)
239-
244+
eessi_software["eessi_version"][eessi_version][file] = parsed_ec["ec"].asdict()
245+
eessi_software["eessi_version"][eessi_version][file]["mtime"] = os.path.getmtime(file)
246+
240247
# Make sure we can load the module before adding it's information to the main dict
241248
try:
242-
eessi_software["eessi_version"][eessi_version][file]['required_modules'] = load_and_list_modules(parsed_ec['full_mod_name'])
249+
eessi_software["eessi_version"][eessi_version][file]["required_modules"] = load_and_list_modules(
250+
parsed_ec["full_mod_name"]
251+
)
243252
except RuntimeError as e:
244253
print(f"Ignoring {file} due to error processing module: {e}")
245254
eessi_software["eessi_version"][eessi_version].pop(file)
246255
continue
247256

248257
# Store everything we now know about the installation as a dict
249258
# Add important data that is related to the module environment
250-
eessi_software["eessi_version"][eessi_version][file]['full_mod_name'] = parsed_ec['full_mod_name']
251-
eessi_software["eessi_version"][eessi_version][file]['short_mod_name'] = parsed_ec['short_mod_name']
252-
eessi_software["eessi_version"][eessi_version][file]['required_modules'] = load_and_list_modules(parsed_ec['full_mod_name'])
259+
eessi_software["eessi_version"][eessi_version][file]["full_mod_name"] = parsed_ec["full_mod_name"]
260+
eessi_software["eessi_version"][eessi_version][file]["short_mod_name"] = parsed_ec["short_mod_name"]
261+
eessi_software["eessi_version"][eessi_version][file]["required_modules"] = load_and_list_modules(
262+
parsed_ec["full_mod_name"]
263+
)
253264
# Retain the easyblocks used so we can use a heuristic to figure out the type of extensions (R, Python, Perl)
254-
eessi_software["eessi_version"][eessi_version][file]['easyblocks'] = easyblocks_used
255-
265+
eessi_software["eessi_version"][eessi_version][file]["easyblocks"] = easyblocks_used
266+
256267
# Store the result
257268
with open(f"eessi_software_{eessi_version}-eb{str(EASYBUILD_VERSION.version[0])}.yaml", "w") as f:
258269
yaml.dump(eessi_software, f)

scripts/generate_schema_md.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33
from pathlib import Path
44

5+
56
def explain_json_schema(obj, indent=0):
67
spacing = " " * indent
78
explanation = ""
@@ -22,6 +23,7 @@ def explain_json_schema(obj, indent=0):
2223
explanation += type(obj).__name__
2324
return explanation
2425

26+
2527
def main():
2628
if len(sys.argv) < 2:
2729
print("Usage: python generate_schema_md.py <path_to_json_file>")
@@ -48,5 +50,6 @@ def main():
4850

4951
print(md_content)
5052

53+
5154
if __name__ == "__main__":
5255
main()

scripts/merge_data_files.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
import yaml
44
from datetime import datetime, timezone
55

6+
67
def earliest_if_within_two_hours(timestamps):
78
if not timestamps:
89
raise ValueError("No timestamps provided")
910

1011
# Parse timestamps into aware datetime objects
11-
times = [
12-
datetime.fromisoformat(t.replace("Z", "+00:00"))
13-
for t in timestamps
14-
]
12+
times = [datetime.fromisoformat(t.replace("Z", "+00:00")) for t in timestamps]
1513

1614
times.sort()
1715
earliest = times[0]
@@ -25,6 +23,7 @@ def earliest_if_within_two_hours(timestamps):
2523
# Return earliest *string*, matching input format
2624
return earliest.isoformat().replace("+00:00", "Z")
2725

26+
2827
def strict_merge(a, b, path=""):
2928
"""Recursively merge dictionary b into a, erroring on mismatched values."""
3029
if not isinstance(a, dict) or not isinstance(b, dict):

0 commit comments

Comments
 (0)