Source code for chiptools.core.preprocessor

import logging
import traceback
import importlib
import inspect
import sys
import os

from chiptools.common.exceptions import FileNotFoundError


log = logging.getLogger(__name__)
preprocessor_temporary_module = 'chiptools_preprocessor_temporary_module'


[docs]def get_preprocessor(path): """Import the Python script supplied by the path and return a handle to a preprocessor function from the import. It is expected that the file to be imported contains a function called 'process' that accepts a list of file data and a file path. If these conditions are not met this function will return None. """ if preprocessor_temporary_module in sys.modules: # Clear the reference to the testPackageModule module # TODO: Although unlikely, it is possible that we may delete an # existing module from the modules list, is there a more robust way of # achieving this functionality? del sys.modules[preprocessor_temporary_module] if not os.path.exists(path): log.error('File not found, aborting preprocessor load: ' + str(path)) return try: # We are loading unchecked user code here, the import stage is # exception checked. importlib.machinery.SourceFileLoader( preprocessor_temporary_module, path, ).load_module() import chiptools_preprocessor_temporary_module # type: ignore except Exception: log.error( 'The module could not be imported due to the ' + ' following error:' ) log.error(traceback.format_exc()) return None # Search the module members until a function with the name 'process' is # found. If no function can be found return None for name, obj in inspect.getmembers( chiptools_preprocessor_temporary_module ): if hasattr(obj, '__name__'): if obj.__name__ == 'process' and callable(obj): return obj return None
[docs]class Preprocessor: """Preprocessor class to handle file preprocessor execution.""" def __init__(self): super(Preprocessor, self).__init__()
[docs] @classmethod def process(cls, path, processor_path): """ Execute the preprocessor on the given file, return True on success """ processor = get_preprocessor(processor_path) if processor is None: print(processor_path + ' not found ') return False try: data = cls.get_file_data(path) except FileNotFoundError: log.error('Preprocessor could not open {0}'.format(path)) return False try: data = processor(data, path) except Exception: log.error( 'The preprocessor caused an exception, ' + 'no modifications were made' ) log.error(traceback.format_exc()) return False cls.set_file_data(path, data) return True
[docs] @classmethod def get_file_data(cls, path): """Return the file data as a list of lines.""" try: with open(path, 'r') as fileToProcess: return fileToProcess.readlines() except FileNotFoundError: log.error('Preprocessor could not open {0}'.format(path))
[docs] @classmethod def set_file_data(cls, path, fileData): """Update the file with the new file data.""" if fileData is None: return with open(path, 'w') as fileToUpdate: for line in fileData: fileToUpdate.write(line)