def _get_pdflatex_exe() -> str: '''Gets the name/path of pdflatex executable in shell''' # XXX: the `which` method used in this function does not work in Windows, # so just default to pdflatex. This is a little hacky and could be # improved. if get_os_name() == 'windows': return 'pdflatex' # attempts (in order) exes = [ 'pdflatex', '/usr/bin/pdflatex', '/usr/local/bin/pdflatex', '/Library/TeX/texbin/pdflatex', # macOS ] # open devnull pipe to write subprocess calls to with open(os.devnull, 'w') as f: # iterate through attempts for exe in exes: # attempt to call which on executable try: exit_code = subprocess.call(['which', exe], stdout=f) if exit_code == 0: return exe except FileNotFoundError: msg.warning('Search for TeX PDF compiler failed.') raise FileNotFoundError # return pdflatex as a default return 'pdflatex'
def tex(self): # check if image exists full_path = Path(self.graphics_path) / Path(self.image_path) if not Path(full_path).exists(): msg.warning(f'Image "{full_path}" could not be found. Replacing ' 'with placeholder text.') graphics = ([ f'{BACKSLASH}texttt{{Image Not Found}}', ]) else: graphics = [ f'{BACKSLASH}includegraphics[width={self.graphics_width}]' f'{{{self.image_path}}}', ] # form figure if self.caption_text: lines = [ f'{BACKSLASH}begin{{figure}}[h!]', f'{BACKSLASH}centering', *graphics, f'{BACKSLASH}caption{{{Text(self.caption_text).tex()}}}' f'{BACKSLASH}end{{figure}}', ] else: lines = [ f'{BACKSLASH}begin{{figure}}[h!]', f'{BACKSLASH}centering', *graphics, f'{BACKSLASH}end{{figure}}', ] return '\n'.join(lines)
def _validate_options(self) -> None: '''Validates options to provide warnings and reset to defaults''' # check fontsize if self.fontsize not in FONT_SIZES: # show warning and enact default msg.warning( 'Option \'fontsize\' must be one of [8pt, 9pt, 10pt, 11pt, ' '12pt, 14pt, 17pt, 20pt]. Defaulting to 10pt.') self.fontsize = '10pt' # reset to default # # check margin if (not is_number(self.margin[:-2]) or not self.margin[-2:] in ['mm', 'cm', 'pt', 'in']): # show warning and enact default msg.warning( 'Option \'margin\' must be a number followed by one of [mm, ' 'cm, pt, in] (e.g. 0.8in). Defaulting to 1.6in.') self.margin = '1.6in' # check linespread if not is_number(self.linespread): # show warning and enact default msg.warning('Option \'linespread\' must be a float (e.g. 1.6). ' 'Defaulting to 1.0.') self.linespread = 1.0 # check nopagestyle if type(self.nopagenumbers) is not bool: # show warning and enact default msg.warning('Option \'nopagenumbers\' takes no parameters. ' 'Simply use :nopagenumbers: on its own.') self.nopagenumbers = False # check nopagestyle if type(self.twocolumn) is not bool: # show warning and enact default msg.warning('Option \'twocolumn\' takes no parameters. ' 'Simply use :twocolumn: on its own.') self.twocolumn = False
def _validate_options(self): # check fontsize if self.fontsize not in FONT_SIZES: # show warning and enact default msg.warning( 'Option "fontsize" must be one of [8pt, 9pt, 10pt, 11pt, ' '12pt, 14pt, 17pt, 20pt]. Defaulting to 10pt.') self.fontsize = '10pt' # reset to default # check margin if (not is_number(self.margin[:-2]) or not self.margin[-2:] in ['mm', 'cm', 'pt', 'in']): # show warning and enact default msg.warning( 'Option "margin" must be a number followed by one of [mm, cm, ' 'pt, in] (e.g. 0.8in). Defaulting to 1.6in.') self.margin = '1.6in' # check linespread if not is_number(self.linespread): # show warning and enact default msg.warning('Option "linespread" must be a float (e.g. 1.6). ' 'Defaulting to 1.0.') self.linespread = 1.0