def verify_pod_links(self, pod): """Check for missing files linked to from POD's html page. See documentation for :class:`~verify_links.LinkVerifier`. This method calls LinkVerifier to check existence of all files linked to from the POD's own top-level html page (after templating). If any files are missing, an error message listing them is written to the run's index.html (located in src/html/pod_missing_snippet.html). """ _log.info('Checking linked output files for %s', pod.name) verifier = verify_links.LinkVerifier( self.POD_HTML(pod), # root HTML file to start search at self.WK_DIR, # root directory to resolve relative paths verbose=False) missing_out = verifier.verify_pod_links(pod.name) if missing_out: _log.error('POD %s has missing output files:\n%s', pod.name, ' \n'.join(missing_out)) template_d = html_templating_dict(pod) template_d['missing_output'] = '<br>'.join(missing_out) util.append_html_template( self.html_src_file('pod_missing_snippet.html'), self.CASE_TEMP_HTML, template_d) pod.exceptions.log( util.MDTFFileNotFoundError( f'Missing {len(missing_out)} files.')) else: _log.info('\tNo files are missing.')
def verify_pod_links(self, pod): """Check for missing files linked to from POD's html page. See documentation for :class:`~src.verify_links.LinkVerifier`. This method calls :class:`~src.verify_links.LinkVerifier` to check existence of all files linked to from the POD's own top-level html page (after templating). If any files are missing, an error message listing them is written to the run's ``index.html`` page (located in ``src/html/pod_missing_snippet.html``). """ pod.log.info('Checking linked output files for %s.', pod.full_name) verifier = verify_links.LinkVerifier( self.POD_HTML(pod), # root html file to start search at self.WK_DIR, # root directory to resolve relative paths verbose=False, log=pod.log) missing_out = verifier.verify_pod_links(pod.name) if missing_out: pod.deactivate( util.MDTFFileNotFoundError( f'Missing {len(missing_out)} files.')) else: pod.log.info('\tNo files are missing.')
def make_pod_html(self, pod): """Perform templating on POD's html results page(s). A wrapper for :func:`~util.append_html_template`. Looks for all html files in POD_CODE_DIR, templates them, and copies them to POD_WK_DIR, respecting subdirectory structure (see doc for :func:`~util.recursive_copy`). """ test_path = os.path.join(pod.POD_CODE_DIR, self.pod_html_template_file_name(pod)) if not os.path.isfile(test_path): # POD's top-level HTML template needs to exist raise util.MDTFFileNotFoundError(test_path) template_d = html_templating_dict(pod) # copy and template all .html files, since PODs can make sub-pages source_files = util.find_files(pod.POD_CODE_DIR, '*.html') util.recursive_copy( source_files, pod.POD_CODE_DIR, pod.POD_WK_DIR, copy_function=(lambda src, dest: util.append_html_template( src, dest, template_dict=template_d, append=False)), overwrite=True)
def convert_pod_figures(self, pod, src_subdir, dest_subdir): """Convert all vector graphics in `POD_WK_DIR/subdir` to .png files using ghostscript. All vector graphics files (identified by extension) in any subdirectory of `POD_WK_DIR/src_subdir` are converted to .png files by running `ghostscript <https://www.ghostscript.com/>`__ in a subprocess. Ghostscript is included in the _MDTF_base conda environment. Afterwards, any bitmap files (identified by extension) in any subdirectory of `POD_WK_DIR/src_subdir` are moved to `POD_WK_DIR/dest_subdir`, preserving and subdirectories (see doc for :func:`~util.recursive_copy`.) Args: src_subdir: Subdirectory tree of `POD_WK_DIR` to search for vector graphics files. dest_subdir: Subdirectory tree of `POD_WK_DIR` to move converted bitmap files to. """ # Flags to pass to ghostscript for PS -> PNG conversion (in particular # bitmap resolution.) eps_convert_flags = ( "-dSAFER -dBATCH -dNOPAUSE -dEPSCrop -r150 " "-sDEVICE=png16m -dTextAlphaBits=4 -dGraphicsAlphaBits=4") abs_src_subdir = os.path.join(pod.POD_WK_DIR, src_subdir) abs_dest_subdir = os.path.join(pod.POD_WK_DIR, dest_subdir) files = util.find_files( abs_src_subdir, ['*.ps', '*.PS', '*.eps', '*.EPS', '*.pdf', '*.PDF']) for f in files: f_stem, _ = os.path.splitext(f) # Append "_MDTF_TEMP" + page number to output files ("%d" = ghostscript's # template for multi-page output). If input .ps/.pdf file has multiple # pages, this will generate 1 png per page, counting from 1. f_out = f_stem + '_MDTF_TEMP_%d.png' try: util.run_shell_command( f'gs {eps_convert_flags} -sOutputFile="{f_out}" {f}') except Exception as exc: _log.error("%s produced malformed plot: %s", pod.name, f[len(abs_src_subdir):]) if isinstance(exc, util.MDTFCalledProcessError): _log.debug( "gs error encountered when converting %s for %s:\n%s", pod.name, f[len(abs_src_subdir):], getattr(exc, "output", "")) continue # gs ran successfully; check how many files it created: out_files = glob.glob(f_stem + '_MDTF_TEMP_?.png') if not out_files: raise util.MDTFFileNotFoundError( f"No .png generated from {f}.") elif len(out_files) == 1: # got one .png, so remove suffix. os.rename(out_files[0], f_stem + '.png') else: # Multiple .pngs. Drop the MDTF_TEMP suffix and renumber starting # from zero (forget which POD requires this.) for n in range(len(out_files)): os.rename(f_stem + f'_MDTF_TEMP_{n+1}.png', f_stem + f'-{n}.png') # move converted figures and any figures that were saved directly as bitmaps files = util.find_files(abs_src_subdir, ['*.png', '*.gif', '*.jpg', '*.jpeg']) util.recursive_copy(files, abs_src_subdir, abs_dest_subdir, copy_function=shutil.move, overwrite=False)