Source code for coseda.initialize.project_files

"""Helpers for project-level INI organization and index lists."""

import configparser
import os
import platform
import psutil
import sys

from coseda.logging_utils import log_print, log_start, shoutout
from coseda.io import handle_input, is_parent_config_file, read_config, config_to_paths


[docs] def find_configfiles(input_path): """Return child INIs (excluding parent configs) resolved from file/folder/list input.""" configfiles, _ = handle_input(input_path) return configfiles
[docs] def resume_processing(input_path): """Refresh stored configfile paths in INIs and log the environment header.""" configfiles, _ = handle_input(input_path) for configfile in configfiles: shoutout(configfile) config = read_config(configfile) config.set('Paths', 'configfile_path', configfile) with open(configfile, 'w', encoding='utf-8') as cfgfile: config.write(cfgfile) _, _, _, logfile_path, _, _ = config_to_paths(configfile) log_start(logfile_path, 'resuming processing, location of .ini file updated') log_start( logfile_path, f'system: {platform.system()} {platform.architecture()}, version {platform.version()}' ) log_start( logfile_path, f'hardware: {psutil.cpu_count(logical=False)} physical cores, ' f'{psutil.cpu_count(logical=True)} logical cores, ' f'{round(psutil.virtual_memory().total / (1024 ** 3))} GB total memory' ) log_start(logfile_path, f'python version {sys.version}')
[docs] def get_parent_ini_file(input_path): """ Accepts an input path which is either a parent INI file or a folder containing one parent INI file. Returns the path to the parent INI file. """ if os.path.isfile(input_path): # Input is a file if input_path.endswith('.ini'): if is_parent_config_file(input_path): return input_path raise ValueError(f"The file '{input_path}' is not a parent INI file.") raise ValueError(f"The file '{input_path}' is not an INI file.") if os.path.isdir(input_path): # Input is a directory ini_files = [os.path.join(input_path, f) for f in os.listdir(input_path) if f.endswith('.ini')] parent_ini_files = [f for f in ini_files if is_parent_config_file(f)] if len(parent_ini_files) == 1: return parent_ini_files[0] if len(parent_ini_files) == 0: raise ValueError(f"No parent INI file found in the directory '{input_path}'.") raise ValueError( f"Multiple parent INI files found in the directory '{input_path}'. Please specify one." ) raise ValueError(f"The input path '{input_path}' is neither a file nor a directory.")
[docs] def write_index_file(input_path): """Build a CrystFEL-compatible .list file from all HDF5 paths in the inputs.""" configfiles, _ = handle_input(input_path) log_print(input_path) h5list = [] for configfile in configfiles: shoutout(configfile) config = read_config(configfile) outputfolder, outputfolder_path, logfile, logfile_path, h5file, h5file_path = config_to_paths(configfile) h5list.append(h5file_path) outputpath = os.path.join(outputfolder_path, 'template.list') with open(outputpath, 'w') as file: for h5 in h5list: file.write(h5 + '\n')
[docs] def generate_parent_ini_file(folder_path, parent_ini_filename=None): # Determine the default parent INI filename if not provided if parent_ini_filename is None: # Get the absolute path to handle cases where folder_path ends with '/' folder_path = os.path.abspath(folder_path) # Get the name of the parent folder parent_folder_name = os.path.basename(folder_path) # Construct the parent INI filename parent_ini_filename = f"{parent_folder_name}.ini" # Use the handle_input function to get all non-parent INI files configfiles, _ = handle_input(folder_path) if not configfiles: message = 'No valid subset INI files found to include in the parent INI file.' log_start(None, message) return None # Create the parent INI file parent_config = configparser.ConfigParser() # Add the General section with config_type = parent parent_config['General'] = {'config_type': 'parent'} # Add the Subsets section parent_config['Subsets'] = {} # Add each child INI file under the Subsets section parent_ini_path = os.path.join(folder_path, parent_ini_filename) parent_dir = os.path.dirname(parent_ini_path) for idx, cfg in enumerate(configfiles, start=1): # Get the relative path to the child INI file relative_path = os.path.relpath(cfg, parent_dir) key_name = f'subset{idx}' parent_config['Subsets'][key_name] = relative_path # Add the Paths section parent_config['Paths'] = {} # Set configfile_path to the absolute path of the parent INI file parent_config['Paths']['configfile_path'] = parent_ini_path # Set logfile to have the same name as the INI file but with .log extension log_filename = os.path.splitext(parent_ini_filename)[0] + '.log' parent_config['Paths']['logfile'] = log_filename # Set framepath (assuming it's a fixed value) parent_config['Paths']['framepath'] = 'entry/data/images' # Write the parent INI file with open(parent_ini_path, 'w') as parent_ini_file: parent_config.write(parent_ini_file) # Construct the log file path log_file_path = os.path.join(folder_path, log_filename) # Use log_start to create the log file and write the initial message if not os.path.exists(log_file_path): initial_message = f"Log file created for {parent_ini_filename}" log_start(log_file_path, initial_message) else: message = f"Log file '{log_filename}' already exists." log_start(log_file_path, message) # Log the creation of the parent INI file message = f"Parent INI file generated at: {parent_ini_path}" log_start(log_file_path, message) # Log the list of child INI files included child_files = ', '.join([os.path.basename(cfg) for cfg in configfiles]) message = f"Subset INI files included: {child_files}" log_start(log_file_path, message) return parent_ini_path