def process_library_filter(self, filt: LibraryFilter, pre_filts: List[Callable[[Library], bool]], output_func: Callable[[str, LibraryFilter], List[str]], must_exist: bool = True, uniquify: bool = True) -> List[str]: """ Process the given library filter and return a list of items from that library filter with any extra post-processing. - Get a list of lib items - Run any extra_post_filter_funcs (if needed) - For every lib item in each lib items, run output_func :param filt: LibraryFilter to check against all libraries. :param pre_filts: List of functions with which to pre-filter the libraries. Each function must return true in order for this library to be used. :param output_func: Function which processes the outputs, taking in the filtered lib and the library filter which generated it. :param must_exist: Must each library item actually exist? Default: True (yes, they must exist) :param uniquify: Must uniqify the list of output files. Default: True :return: Resultant items from the filter and post-processed. (e.g. --timing foo.db --timing bar.db) """ # First, filter the list of available libraries with pre_filts and the library itself. lib_filters = pre_filts + get_or_else( optional_map(filt.filter_func, lambda x: [x]), []) filtered_libs = list( reduce_named(sequence=lib_filters, initial=self.get_available_libraries(), function=lambda libs, func: filter(func, libs)) ) # type: List[Library] # Next, sort the list of libraries if a sort function exists. if filt.sort_func is not None: filtered_libs = sorted(filtered_libs, key=filt.sort_func) # Next, extract paths and prepend them to get the real paths. def get_and_prepend_path(lib: Library) -> Tuple[Library, List[str]]: paths = filt.paths_func(lib) full_paths = list( map(lambda path: self.prepend_dir_path(path, lib), paths)) return lib, full_paths libs_and_paths = list( map(get_and_prepend_path, filtered_libs)) # type: List[Tuple[Library, List[str]]] # Existence checks for paths. def check_lib_and_paths( inp: Tuple[Library, List[str]]) -> Tuple[Library, List[str]]: lib = inp[0] # type: Library paths = inp[1] # type: List[str] existence_check_func = self.make_check_isfile( filt.description) if filt.is_file else self.make_check_isdir( filt.description) paths = list(map(existence_check_func, paths)) return lib, paths if must_exist: libs_and_paths = list(map(check_lib_and_paths, libs_and_paths)) # Now call the extraction function to get a final list of strings. # If no extraction function was specified, use the identity extraction # function. def identity_extraction_func(lib: "Library", paths: List[str]) -> List[str]: return paths extraction_func = get_or_else(filt.extraction_func, identity_extraction_func) output_list = reduce_list_str( add_lists, list(map(lambda t: extraction_func(t[0], t[1]), libs_and_paths)), []) # type: List[str] # Quickly check that it is actually a List[str]. if not isinstance(output_list, List): raise TypeError("output_list is not a List[str], but a " + str(type(output_list))) for i in output_list: if not isinstance(i, str): raise TypeError("output_list is a List but not a List[str]") # Uniquify results. # TODO: think about whether this really belongs here and whether we always need to uniquify. # This is here to get stuff working since some CAD tools dislike duplicated arguments (e.g. duplicated stdcell # lib, etc). if uniquify: in_place_unique(output_list) # Apply any list-level functions. after_post_filter = reduce_named( sequence=filt.extra_post_filter_funcs, initial=output_list, function=lambda libs, func: func(list(libs)), ) # Finally, apply any output functions. # e.g. turning foo.db into ["--timing", "foo.db"]. after_output_functions = list( map(lambda item: output_func(item, filt), after_post_filter)) # Concatenate lists of List[str] together. return reduce_list_str(add_lists, after_output_functions, [])
def process_library_filter(self, filt: LibraryFilter, pre_filts: List[Callable[[Library], bool]], output_func: Callable[[str, LibraryFilter], List[str]], must_exist: bool = True, uniquify: bool = True) -> List[str]: """ Process the given library filter and return a list of items from that library filter with any extra post-processing. - Get a list of lib items - Run any extra_post_filter_funcs (if needed) - For every lib item in each lib items, run output_func :param filt: LibraryFilter to check against all libraries. :param pre_filts: List of functions with which to pre-filter the libraries. Each function must return true in order for this library to be used. :param output_func: Function which processes the outputs, taking in the filtered lib and the library filter which generated it. :param must_exist: Must each library item actually exist? Default: True (yes, they must exist) :param uniquify: Must uniqify the list of output files. Default: True :return: Resultant items from the filter and post-processed. (e.g. --timing foo.db --timing bar.db) """ # First, filter the list of available libraries with pre_filts and the library itself. lib_filters = pre_filts + get_or_else(optional_map(filt.filter_func, lambda x: [x]), []) filtered_libs = list(reduce_named( sequence=lib_filters, initial=self.get_available_libraries(), function=lambda libs, func: filter(func, libs) )) # type: List[Library] # Next, sort the list of libraries if a sort function exists. if filt.sort_func is not None: filtered_libs = sorted(filtered_libs, key=filt.sort_func) # Next, extract paths and prepend them to get the real paths. def get_and_prepend_path(lib: Library) -> Tuple[Library, List[str]]: paths = filt.paths_func(lib) full_paths = list(map(lambda path: self.prepend_dir_path(path, lib), paths)) return lib, full_paths libs_and_paths = list(map(get_and_prepend_path, filtered_libs)) # type: List[Tuple[Library, List[str]]] # Existence checks for paths. def check_lib_and_paths(inp: Tuple[Library, List[str]]) -> Tuple[Library, List[str]]: lib = inp[0] # type: Library paths = inp[1] # type: List[str] existence_check_func = self.make_check_isfile(filt.description) if filt.is_file else self.make_check_isdir( filt.description) paths = list(map(existence_check_func, paths)) return lib, paths if must_exist: libs_and_paths = list(map(check_lib_and_paths, libs_and_paths)) # Now call the extraction function to get a final list of strings. # If no extraction function was specified, use the identity extraction # function. def identity_extraction_func(lib: "Library", paths: List[str]) -> List[str]: return paths extraction_func = get_or_else(filt.extraction_func, identity_extraction_func) output_list = reduce_list_str(add_lists, list(map(lambda t: extraction_func(t[0], t[1]), libs_and_paths)), []) # type: List[str] # Quickly check that it is actually a List[str]. if not isinstance(output_list, List): raise TypeError("output_list is not a List[str], but a " + str(type(output_list))) for i in output_list: if not isinstance(i, str): raise TypeError("output_list is a List but not a List[str]") # Uniquify results. # TODO: think about whether this really belongs here and whether we always need to uniquify. # This is here to get stuff working since some CAD tools dislike duplicated arguments (e.g. duplicated stdcell # lib, etc). if uniquify: in_place_unique(output_list) # Apply any list-level functions. after_post_filter = reduce_named( sequence=filt.extra_post_filter_funcs, initial=output_list, function=lambda libs, func: func(list(libs)), ) # Finally, apply any output functions. # e.g. turning foo.db into ["--timing", "foo.db"]. after_output_functions = list(map(lambda item: output_func(item, filt), after_post_filter)) # Concatenate lists of List[str] together. return reduce_list_str(add_lists, after_output_functions, [])