def __init__(self, read_system_config: bool = True, read_user_config: bool = True, args: list = None, exiter: AutoLaTeXExiter = None): ''' Constructor. :param read_system_config: Indicates if the system-level configuration must be read. Default is True. :type read_system_config: bool :param read_user_config: Indicates if the user-level configuration must be read. Default is True. :type read_user_config: bool :param args: List of command line arguments. If it is None, the system args are used. :type args: list :param exiter: The instance of the object that is called when AutoLaTeX should stop. :type exister: AutoLaTeXExiter ''' self.__initial_argv = args self.__read_document_configuration = True if exiter: self.__exiter = exiter else: self.__exiter = AutoLaTeXExiter() # Create the AutoLaTeX configuration object self.configuration = Config() # Initialization of the logging system (must be after configuration creation) self.__logging_handler = None self._init_logging_system() # Initialization that depends on the script itself script_launchname = os.path.basename(os.sys.argv[0]) (script_path, script_ext) = os.path.splitext(os.sys.argv[0]) script_name = os.path.basename(script_path) self.configuration.name = script_name self.configuration.launchName = script_launchname # Read the configuration from the system config_reader = OldStyleConfigReader() if read_system_config: config_reader.readSystemConfigSafely(self.configuration) # Read the configuration from the user home if read_user_config: config_reader.readUserConfigSafely(self.configuration) # Create the CLI parser self._cli_parser = self._create_cli_parser( name=self.configuration.name, version=self.configuration.version, epilog=self._build_help_epilog())
def _read_generation_prefix(self, content : object, filename : str, config : Config): ''' Read the path definition in the configuration section [generation]. :param content: the configuration file content. :type content: dict :param filename: the name of the configuration file. :type filename: str :param config: the configuration object to fill up. :type config: Config ''' main_name = self._ensureAscendentCompatibility(content.get('main file')) if main_name: main_name = genutils.abspath(main_name, self._base_dir) config.documentDirectory = os.path.dirname(main_name) config.documentFilename = os.path.basename(main_name)
def setUp(self): logging.getLogger().setLevel(logging.CRITICAL) self.__config = Config() self._dir = os.path.normpath( os.path.join(os.path.dirname(__file__), '..', 'dev-resources')) self.__filename = os.path.join(self._dir, 'config.ini') self.__reader = configreader.OldStyleConfigReader() self.__cfg = self.__reader.read(self.__filename, TranslatorLevel.USER) self.assertIsNotNone(self.__cfg)
def setUp(self): logging.getLogger().setLevel(logging.CRITICAL) self.directory = generateTranslatorStubs() self.config = Config() self.config.translators.is_translator_fileformat_1_enable = True self.repo = TranslatorRepository(self.config) translators = self.repo._readDirectory(directory=self.directory, recursive=True, warn=False) for translator in translators: self.repo._installedTranslators[ TranslatorLevel.USER][translator] = translators[translator] self.repo._installedTranslatorNames.add(translator)
def setUp(self): ensureAutoLaTeXLoggingLevels() logging.getLogger().setLevel(logging.CRITICAL) self.directory1 = generateTranslatorStubsForGeneration() self.directory2 = generateImageStubs() self.config = Config() self.config.translators.is_translator_fileformat_1_enable = True self.config.translators.ignoreSystemTranslators = True self.config.translators.ignoreUserTranslators = True self.config.translators.ignoreDocumentTranslators = True self.config.translators.includePaths = [self.directory1] self.config.translators.imagePaths = [self.directory2] self.repo = TranslatorRepository(self.config) self.runner = TranslatorRunner(self.repo)
def readUserConfigSafely(self, config : Config = None) -> Config: ''' Read the configuration file at the user level without failing if the file does not exist. :param config: the configuration object to fill up. Default is None. :type config: Config :return: the configuration object :rtype: Config ''' if config is None: config = Config() filename = config.userConfigFile if filename and os.path.isfile(filename) and os.access(filename, os.R_OK): try: self.read(filename, TranslatorLevel.USER, config) except: pass return config
def read(self, filename : str, translator_level : TranslatorLevel, config : Config = None) -> Config: ''' Read the configuration file. :param filename: the name of the file to read. :type filename: str :param translator_level: the level at which the configuration is located. See TranslatorLevel enumeration. :type translator_level: TranslatorLevel :param config: the configuration object to fill up. Default is None. :type config: Config :return: the configuration object :rtype: Config ''' if config is None: config = Config() filename = os.path.abspath(filename) self._base_dir = os.path.dirname(filename) try: config_file = configparser.SafeConfigParser() config_file.read(filename) for section in config_file.sections(): nsection = section.lower() if nsection == 'generation': content = dict(config_file.items(section)) self._read_generation_prefix(content, filename, config) for section in config_file.sections(): nsection = section.lower() content = dict(config_file.items(section)) if nsection == 'generation': self._read_generation(content, config) elif nsection == 'viewer': self._read_viewer(content, config) elif nsection == 'clean': self._read_clean(content, config) elif nsection == 'scm': self._read_scm(content, config) elif self._is_translator_section(nsection): self._read_translator(section, translator_level, content, config) else: logging.debug(_T("Ignore section '%s' in the configuration file: %s") % (section, filename)) finally: self._base_dir = os.getcwd() return config
def readDocumentConfigSafely(self, filename : str, config : Config = None) -> Config: ''' Read the configuration file at the document level without failing if the file does not exist. :param filename: the name of the file to read. :type filename: str :param config: the configuration object to fill up. Default is None. :type config: Config :return: the configuration object :rtype: Config ''' if config is None: config = Config() if filename and os.path.isfile(filename) and os.access(filename, os.R_OK): try: self.read(filename, TranslatorLevel.DOCUMENT, config) except: pass return config
def setUp(self): logging.getLogger().setLevel(logging.CRITICAL) self.directory = generateTranslatorStubsWithConflicts() self.config = Config() self.config.translators.is_translator_fileformat_1_enable = True self.repo = TranslatorRepository(self.config) translators = self.repo._readDirectory(directory=self.directory, recursive=True, warn=False) for translator in translators: self.repo._installedTranslators[1][translator] = translators[ translator] self.repo._installedTranslatorNames.add(translator) self.config.translators.setIncluded('svg2pdf', TranslatorLevel.SYSTEM, False) self.config.translators.setIncluded('svg2pdf', TranslatorLevel.DOCUMENT, True) self.config.translators.setIncluded('svg2png', TranslatorLevel.SYSTEM, True) self.config.translators.setIncluded('dot2pdf', TranslatorLevel.USER, False)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.__interpreter = None self.__config = Config()
def write(self, filename : str, config : Config): ''' Write the configuration file. :param filename: the name of the file to read. :type filename: str :param config: the configuration object to fill up. :type config: Config ''' dout = os.path.dirname(filename) config_out = configparser.ConfigParser() config_out.add_section('generation') self.set(config_out, 'generation', 'main file', self.to_path(os.path.normpath(os.path.join(config.documentDirectory, config.documentFilename)), dout)) self.set(config_out, 'generation', 'image directory', self.to_paths(config.translators.imagePaths, dout)) self.set(config_out, 'generation', 'generate images', self.to_bool(config.translators.is_translator_enable)) self.set(config_out, 'generation', 'generation type', 'pdf' if config.generation.pdfMode else 'ps') self.set(config_out, 'generation', 'tex compiler', config.generation.latexCompiler) self.set(config_out, 'generation', 'synctex', self.to_bool(config.generation.synctex)) self.set(config_out, 'generation', 'translator include path', self.to_paths(config.translators.includePaths, dout) ) self.set(config_out, 'generation', 'latex_cmd', self.to_cli(config.generation.latexCLI)) self.set(config_out, 'generation', 'latex_flags', self.to_cli(config.generation.latexFlags)) self.set(config_out, 'generation', 'bibtex_cmd', self.to_cli(config.generation.bibtexCLI)) self.set(config_out, 'generation', 'bibtex_flags', self.to_cli(config.generation.bibtexFlags)) self.set(config_out, 'generation', 'biber_cmd', self.to_cli(config.generation.biberCLI)) self.set(config_out, 'generation', 'biber_flags', self.to_cli(config.generation.biberFlags)) self.set(config_out, 'generation', 'makeglossaries_cmd', self.to_cli(config.generation.makeglossaryCLI)) self.set(config_out, 'generation', 'makeglossaries_flags', self.to_cli(config.generation.makeglossaryFlags)) self.set(config_out, 'generation', 'makeindex_cmd', self.to_cli(config.generation.makeindexCLI)) self.set(config_out, 'generation', 'makeindex_flags', self.to_cli(config.generation.makeindexFlags)) self.set(config_out, 'generation', 'dvi2ps_cmd', self.to_cli(config.generation.dvipsCLI)) self.set(config_out, 'generation', 'dvi2ps_flags', self.to_cli(config.generation.dvipsFlags)) if config.generation.makeindexStyleFilename: if config.generation.makeindexStyleFilename == config.get_system_ist_file(): self.set(config_out, 'generation', 'makeindex style', '@system') elif os.path.dirname(config.generation.makeindexStyleFilename) == config.documentDirectory: self.set(config_out, 'generation', 'makeindex style', '@detect@system') else: self.set(config_out, 'generation', 'makeindex style', config.generation.makeindexStyleFilename) config_out.add_section('viewer') self.set(config_out, 'viewer', 'view', self.to_bool(config.view.view)) self.set(config_out, 'viewer', 'viewer', self.to_cli(config.view.viewerCLI)) clean_files = config.clean.cleanFiles cleanall_files = config.clean.cleanallFiles if clean_files or cleanall_files: config_out.add_section('clean') self.set(config_out, 'clean', 'files to clean', self.to_paths(clean_files, dout)) self.set(config_out, 'clean', 'files to desintegrate', self.to_paths(cleanall_files, dout)) for translator, included in config.translators.translators().items(): config_out.add_section(translator) self.set(config_out, translator, 'include module', self.to_bool(included)) with open(filename, 'w') as configfile: config_out.write(configfile)
def _read_generation(self, content : object, config : Config): ''' Read the configuration section [generation], except the ones "_read_generation_prefix". :param content: the configuration file content. :type content: dict :param config: the configuration object to fill up. :type config: Config ''' for p in OldStyleConfigReader.to_path_list(self._ensureAscendentCompatibility(content.get('image directory'))): config.translators.addImagePath(self.to_path(p)) config.translators.is_translator_enable = OldStyleConfigReader.to_bool(self._ensureAscendentCompatibility(content.get('generate images')), config.translators.is_translator_enable) generation_type = OldStyleConfigReader.to_kw(self._ensureAscendentCompatibility(content.get('generation type')), 'pdf' if config.generation.pdfMode else 'ps') if generation_type == 'dvi' or generation_type == 'ps': config.generation.pdfMode = False else: config.generation.pdfMode = True tex_compiler = OldStyleConfigReader.to_kw(self._ensureAscendentCompatibility(content.get('tex compiler')), config.generation.latexCompiler) if tex_compiler != 'latex' and tex_compiler != 'xelatex' and tex_compiler != 'lualatex': tex_compiler = 'pdflatex' config.generation.latexCompiler = tex_compiler config.generation.synctex = OldStyleConfigReader.to_bool(self._ensureAscendentCompatibility(content.get('synctex')), config.generation.synctex) for p in OldStyleConfigReader.to_path_list(self._ensureAscendentCompatibility(content.get('translator include path'))): config.translators.addIncludePath(self.to_path(p)) cmd = self._ensureAscendentCompatibility(content.get('latex_cmd')) if cmd: config.generation.latexCLI = cmd cmd = self._ensureAscendentCompatibility(content.get('bibtex_cmd')) if cmd: config.generation.bibtexCLI = cmd cmd = self._ensureAscendentCompatibility(content.get('biber_cmd')) if cmd: config.generation.biberCLI = cmd cmd = self._ensureAscendentCompatibility(content.get('makeglossaries_cmd')) if cmd: config.generation.makeglossaryCLI = cmd cmd = self._ensureAscendentCompatibility(content.get('makeindex_cmd')) if cmd: config.generation.makeindexCLI = cmd cmd = self._ensureAscendentCompatibility(content.get('dvi2ps_cmd')) if cmd: config.generation.dvipsCLI = cmd flags = self._ensureAscendentCompatibility(content.get('latex_flags')) if flags: config.generation.latexFlags = flags flags = self._ensureAscendentCompatibility(content.get('bibtex_flags')) if flags: config.generation.bibtexFlags = flags flags = self._ensureAscendentCompatibility(content.get('biber_flags')) if flags: config.generation.biberFlags = flags flags = self._ensureAscendentCompatibility(content.get('makeglossaries_flags')) if flags: config.generation.makeglossaryFlags = flags flags = self._ensureAscendentCompatibility(content.get('makeindex_flags')) if flags: config.generation.makeindexFlags = flags flags = self._ensureAscendentCompatibility(content.get('dvi2ps_flags')) if flags: config.generation.dvipsFlags = flags make_index_style = self.to_list(self._ensureAscendentCompatibility(content.get('makeindex style'))) config.generation.makeindexStyleFilename = None if not make_index_style: make_index_style = ['@detect@system'] for key in make_index_style: kw = OldStyleConfigReader.to_kw(key, '@detect@system') result = None if kw == '@detect': result = self.to_path(self.__detect_ist_file(config)) elif kw == '@system': result = self.to_path(config.get_system_ist_file()) elif kw == '@none': config.generation.makeindexStyleFilename = None break elif kw == '@detect@system': ist_file = self.__detect_ist_file(config) if ist_file: result = self.to_path(ist_file) else: result = self.to_path(config.get_system_ist_file()) else: result = self.to_path(make_index_style) if result: config.generation.makeindexStyleFilename = result break
def setUp(self): logging.getLogger().setLevel(logging.CRITICAL) self.__dirname = os.path.dirname(os.path.realpath(__file__)) self.__config = Config() self.__config.osname = 'posix' self.__config.homedir = os.path.join('', 'home')
def __init__(self, config: Config, *, isdir: bool): Config.__init__(self) self.__isDir = isdir self.osname = config.osname self.homedir = config.homedir
def setUp(self): logging.getLogger().setLevel(logging.CRITICAL) self.config = Config() self.config.translators.is_translator_fileformat_1_enable = True
def setUp(self): logging.getLogger().setLevel(logging.CRITICAL) self.directory = generateTranslatorStubs() self.config = Config() self.config.translators.is_translator_fileformat_1_enable = True self.repo = TranslatorRepository(self.config)
class AbstractAutoLaTeXMain(ABC): ''' Main program implementation for AutoLaTeX. ''' def __init__(self, read_system_config: bool = True, read_user_config: bool = True, args: list = None, exiter: AutoLaTeXExiter = None): ''' Constructor. :param read_system_config: Indicates if the system-level configuration must be read. Default is True. :type read_system_config: bool :param read_user_config: Indicates if the user-level configuration must be read. Default is True. :type read_user_config: bool :param args: List of command line arguments. If it is None, the system args are used. :type args: list :param exiter: The instance of the object that is called when AutoLaTeX should stop. :type exister: AutoLaTeXExiter ''' self.__initial_argv = args self.__read_document_configuration = True if exiter: self.__exiter = exiter else: self.__exiter = AutoLaTeXExiter() # Create the AutoLaTeX configuration object self.configuration = Config() # Initialization of the logging system (must be after configuration creation) self.__logging_handler = None self._init_logging_system() # Initialization that depends on the script itself script_launchname = os.path.basename(os.sys.argv[0]) (script_path, script_ext) = os.path.splitext(os.sys.argv[0]) script_name = os.path.basename(script_path) self.configuration.name = script_name self.configuration.launchName = script_launchname # Read the configuration from the system config_reader = OldStyleConfigReader() if read_system_config: config_reader.readSystemConfigSafely(self.configuration) # Read the configuration from the user home if read_user_config: config_reader.readUserConfigSafely(self.configuration) # Create the CLI parser self._cli_parser = self._create_cli_parser( name=self.configuration.name, version=self.configuration.version, epilog=self._build_help_epilog()) def _build_command_dict(self, package_name) -> dict: ''' Build the dictionnary that maps the command's names to AutoLaTeXCommand. :param package_name: The name of the package to explore. :type package_name: str :return: the dict of the commands. :rtype: dict ''' execEnv = { 'modules': None, } exec( "import " + package_name + "\nmodules = " + package_name + ".__all__", None, execEnv) modules = execEnv['modules'] ids = dict() for module in modules: execEnv = { 'id': None, 'alias': None, 'type': None, 'help': None, } cmd = textwrap.dedent('''\ from %s.%s import MakerAction type = MakerAction id = MakerAction.id help = MakerAction.help try: alias = MakerAction.alias except: alias = None ''') % (package_name, module) exec(cmd, None, execEnv) id = execEnv['id'] ids[id] = AutoLaTeXCommand(name=id, type=execEnv['type'], help=execEnv['help'], alias=execEnv['alias']) return ids def _create_cli_arguments_for_commands(self, commands: dict, title: str, help: str, metavar: str = 'COMMAND'): ''' Create CLI arguments for the given commands. :param commands: the pairs "command id"-"command instance". :type commands: dict :param title: The title of the command set. :type title: str :param help: The help description of the command set. :type help: str :param metavar: The name of the command set in the help. Default is: COMMAND. :type metavar: str ''' subparsers = self.cli_parser.add_subparsers(title=title, metavar=(metavar), help=help) for id, command in commands.items(): command.instance.register_command(action_parser=subparsers, command=command, configuration=self.configuration) def __parse_command_with_sequence_of_commands_single(self, cli: str) -> tuple: unknown_arguments = list() commands = list() self._cli_parser.exit_on_error = False while cli: # Create a "local" namespace to avoid implicit inheritence of optional option values between commands. # This principle works because the values of the global optional arguments are not stored into the namespace but inside the AutoLaTeX configuration. args, cli1 = self._cli_parser.parse_known_args(cli) if cli1: unknown_arguments.extend(cli1) if args and hasattr(args, '__command_callback_func'): func = getattr(args, '__command_callback_func') if func: tpl = (func, args) commands.append(tpl) if cli1 == cli: # Nothing was consumed return (commands, unknown_arguments) cli = cli1 return (commands, unknown_arguments) def _parse_command_with_sequence_of_commands(self) -> str: ''' Parse the command line in order to detect the optional arguments and the sequence of command arguments :return: the tuple with as first element the CLI commands, and the second element the list of unknown arguments. :rtype: tuple (commands, list) ''' if self.__initial_argv is None or not isinstance( self.__initial_argv, list): cli = sys.argv[1:] else: cli = list(self.__initial_argv) (commands, unknown_arguments ) = self.__parse_command_with_sequence_of_commands_single(cli) # Check if a command is provided; and add the default command. if not commands: default_action = self.configuration.defaultCliAction if default_action: cli.insert(0, default_action) (commands, unknown_arguments ) = self.__parse_command_with_sequence_of_commands_single(cli) return (commands, unknown_arguments) def _create_default_command_arg_namespace(self) -> argparse.Namespace: ''' Create the namespace that corresponds to a default command. :return: the namespace :rtype: Namespace ''' namespace = argparse.Namespace() # add any action defaults that aren't present for action in self._cli_parser._actions: if action.dest is not SUPPRESS and not hasattr( namespace, action.dest) and action.default is not SUPPRESS: setattr(namespace, action.dest, action.default) # add any parser defaults that aren't present for dest in self._cli_parser._defaults: if not hasattr(namespace, dest): setattr(namespace, dest, self._defaults[dest]) return namespace def _exitOnFailure(self): ''' Exit the main program on failure. ''' self.__exiter.exitOnFailure() def _exitOnSuccess(self): ''' Exit the main program on success. ''' self.__exiter.exitOnSuccess() def _exitOnException(self, exception): ''' Exit the main program on exception. :param exception: The exception. :type exception: exception ''' self.__exiter.exitOException(exception) def _execute_commands(self, args: list, all_commands: dict): ''' Execute the commands. :param args: List of arguments on the command line. :type args: list of argparse objects :param all_commands: Dict of all the available commands. :type all_commands: dict ''' # Check existing command if not args: logging.error(_T('Unable to determine the command to run')) self.exitOnFailure() return # Run the sequence of commands for cmd, cmd_args in args: try: continuation = cmd(cmd_args) if not continuation: self._exitOnSuccess() return except BaseException as excp: logging.error( _T('Error when running the command: %s') % (str(excp))) self.__exiter.exitOnException(excp) return def _build_help_epilog(self) -> str: ''' Build a string that could serve as help epilog. :return: the epilog text. :rtype: str ''' return None def _init_logging_system(self): ''' Configure the logging system. ''' logging.basicConfig(format=self.configuration.logging.message, level=self.configuration.logging.level) def _detect_autolatex_configuration_file(self, directory: str) -> str: ''' Search for an AutoLaTeX configuration file in the given directory or one of its parent directories. :param directory: The start of the search. :type directory: str :return: the path to the configuration file, or None. :rtype: str ''' if directory: root = os.path.abspath(os.sep) if os.path.isdir(directory): path = os.path.abspath(directory) else: path = os.path.dirname(os.path.abspath(directory)) while (path and path != root and os.path.isdir(path)): filename = self.configuration.makeDocumentConfigFilename(path) if filename and os.path.isfile(filename): return filename path = os.path.dirname(path) return None def _create_cli_parser(self, name: str, version: str, default_arg=None, description: str = None, osname: str = None, platformname: str = None, epilog=None): ''' Create the instance of the CLI parser. :param name: The name of the program. :type name: str :param version: The version of the program. :type version: str :param default_arg: The default argument for the program. :type default_arg: str :param description: The description of the program. :type description: str :param osname: The name of the operating system. :type osname: str :param platformname: The name of the platform. :type platformname: str :param epilog: The epilog of the documentation. :type epilog: str :return: the created instance. ''' if not description: description = _T( 'AutoLaTeX is a tool for managing small to large sized LaTeX documents. The user can easily perform all required steps to do such tasks as: preview the document, or produce a PDF file. AutoLaTeX will keep track of files that have changed and how to run the various programs that are needed to produce the output. One of the best feature of AutoLaTeX is to provide translator rules (aka. translators) to automatically generate the figures which will be included into the PDF.' ) if not osname: osname = os.name if not platformname: platformname = platform.system() parser = argparse.ArgumentParser( prog=name, argument_default=default_arg, description=description, epilog=epilog, formatter_class=argparse.RawTextHelpFormatter) parser.version = _T("%s %s - %s/%s platform") % (name, version, osname, platformname) return parser @property def cli_parser(self): ''' Replies the CLI parser. :rtype: argparse object. ''' return self._cli_parser def _add_standard_cli_options_general(self): ''' Add standard CLI options in the "general" category. ''' # --version self._cli_parser.add_argument( '--version', action='version', help=_T('Display the version of AutoLaTeX')) def _add_standard_cli_options_path(self): ''' Add standard CLI options in the "path configuration" category. ''' path_group = self._cli_parser.add_argument_group( _T('path optional arguments')) input_method_group = path_group.add_mutually_exclusive_group() # --directory class DirectoryAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): if os.path.isdir(value): self.configuration.documentDirectory = value self.configuration.documentFilename = None else: logging.error(_T("Invalid directory: %s") % (value)) self.__exiter.exitOnFailure() return input_method_group.add_argument( '-d', '--directory', action=DirectoryAction, help=_T( 'Specify a directory in which a LaTeX document to compile is located. You could specify this option for each directory in which you have a LaTeX document to treat' )) # --file class FileAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): if os.path.isfile(value): self.configuration.setDocumentDirectoryAndFilename(value) else: logging.error(_T("File not found: %s") % (value)) self.__exiter.exitOnFailure() return input_method_group.add_argument( '-f', '--file', action=FileAction, metavar=('TEX_FILE'), help=_T( 'Specify the main LaTeX file to compile. If this option is not specified, AutoLaTeX will search for a TeX file in the current directory' )) # --search-project-from class SearchProjectFromAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): if value: config_file = self._detect_autolatex_configuration_file( value) else: config_file = self._detect_autolatex_configuration_file( self.configuration.documentDirectory) if config_file: config_reader = OldStyleConfigReader() config_reader.readDocumentConfigSafely( config_file, self.configuration) self.__read_document_configuration = False path_group.add_argument( '--search-project-from', action=SearchProjectFromAction, metavar=('FILE'), help=_T( 'When this option is specified, AutoLaTeX is searching a project configuration file (usually \'.autolatex_project.cfg\' on Unix platforms) in the directory of the specified FILE or in one of its ancestors' )) def _add_standard_cli_options_output(self): ''' Add standard CLI options in the "output configuration" category. ''' output_group = self._cli_parser.add_argument_group( _T('output optional arguments')) output_type_group = output_group.add_mutually_exclusive_group() # --pdf class PdfAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.pdfMode = True output_type_group.add_argument( '--pdf', action=PdfAction, nargs=0, help=_T('Do the compilation to produce a PDF document')) # --dvi # --ps class DvipsAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.pdfMode = False output_type_group.add_argument( '--dvi', '--ps', action=DvipsAction, nargs=0, help=_T( 'Do the compilation to produce a DVI, XDV or Postscript document' )) # --stdout # --stderr class StdouterrAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): eprintpkg.is_standard_output = actionself.const std_output_group = output_group.add_mutually_exclusive_group() std_output_group.add_argument( '--stdout', action=StdouterrAction, const=True, nargs=0, help=_T( 'All the standard messages (no log message) are printed out on the standard output (stdout) of the process' )) std_output_group.add_argument( '--stderr', action=StdouterrAction, const=False, nargs=0, help=_T( 'All the standard messages (no log message) are printed out on the standard error output (stderr) of the process' )) def _add_standard_cli_options_tex(self): ''' Add standard CLI options in the "tex configuration" category. ''' tex_group = self._cli_parser.add_argument_group( _T('TeX optional arguments')) tex_tool_group = tex_group.add_mutually_exclusive_group() # --pdflatex class PdflatexCmdAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.latexCompiler = 'pdflatex' tex_tool_group.add_argument( '--pdflatex', action=PdflatexCmdAction, nargs=0, help=_T('Use the LaTeX command: \'pdflatex\'')) # --latex class LatexCmdAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.latexCompiler = 'latex' tex_tool_group.add_argument( '--latex', action=LatexCmdAction, nargs=0, help=_T('Use the historical LaTeX command: \'latex\'')) # --lualatex class LualatexCmdAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.latexCompiler = 'lualatex' tex_tool_group.add_argument( '--lualatex', action=LualatexCmdAction, nargs=0, help=_T('Use the LaTeX command: \'lualatex\'')) # --xelatex class XelatexCmdAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.latexCompiler = 'xelatex' tex_tool_group.add_argument( '--xelatex', action=XelatexCmdAction, nargs=0, help=_T('Use the LaTeX command: \'xelatex\'')) # --synctex # --nosynctex synctex_group = tex_group.add_mutually_exclusive_group() class SynctexAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.generation.synctex = actionself.const synctex_group.add_argument( '--synctex', action=SynctexAction, const=True, nargs=0, help=_T('Enable the generation of the output file with SyncTeX')) synctex_group.add_argument( '--nosynctex', action=SynctexAction, const=False, nargs=0, help=_T('Disable the generation of the output file with SyncTeX')) def _add_standard_cli_options_translator(self): ''' Add standard CLI options in the "translator configuration" category. ''' translator_group = self._cli_parser.add_argument_group( _T('translator optional arguments')) # --auto # --noauto class AutoAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.translators.is_translator_enable = actionself.const enable_translator_group = translator_group.add_mutually_exclusive_group( ) enable_translator_group.add_argument( '--auto', action=AutoAction, const=True, nargs=0, help=_T('Enable the auto generation of the figures')) enable_translator_group.add_argument( '--noauto', action=AutoAction, const=False, nargs=0, help=_T('Disable the auto generation of the figures')) # --exclude class ExcludeAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.translators.setIncluded( value, TranslatorLevel.DOCUMENT, False) translator_group.add_argument( '-e', '--exclude', action=ExcludeAction, metavar=('TRANSLATOR'), help=_T('Avoid AutoLaTeX to load the translator named TRANSLATOR')) # --include class IncludeAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.translators.addIncludePath( value, TranslatorLevel.DOCUMENT, True) translator_group.add_argument( '-i', '--include', action=IncludeAction, metavar=('TRANSLATOR'), help=_T('Force AutoLaTeX to load the translator named TRANSLATOR')) # --include-path class IncludePathAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): paths = genutils.to_path_list( value, self.configuration.documentDirectory) for path in paths: self.configuration.translators.addIncludePath(path) translator_group.add_argument( '-I', '--include-path', action=IncludePathAction, metavar=('PATH'), help=_T( 'Notify AutoLaTeX that it could find translator scripts inside the specified directories. The specified PATH could be a list of paths separated by the operating system\'s path separator (\':\' for Unix, \';\' for Windows for example)' )) # --imgdirectory class ImgDirectoryAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): paths = genutils.to_path_list( value, self.configuration.documentDirectory) for path in paths: self.configuration.translators.addImagePath(path) translator_group.add_argument( '-D', '--imgdirectory', action=ImgDirectoryAction, metavar=('DIRECTORY'), help=_T( 'Specify a directory inside which AutoLaTeX will find the pictures which must be processed by the translators. Each time this option is put on the command line, a directory is added inside the list of the directories to explore' )) def _add_standard_cli_options_biblio(self): ''' Add standard CLI options in the "bibliography configuration" category. ''' biblio_group = self._cli_parser.add_argument_group( _T('bibliography optional arguments')) # --biblio # --nobiblio class BiblioAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.generation.is_biblio_enable = actionself.const enable_biblio_group = biblio_group.add_mutually_exclusive_group() enable_biblio_group.add_argument( '--biblio', action=BiblioAction, const=True, nargs=0, help=_T( 'Enable the call to the bibliography tool (BibTeX, Biber...)')) enable_biblio_group.add_argument( '--nobiblio', action=BiblioAction, const=False, nargs=0, help=_T( 'Disable the call to the bibliography tool (BibTeX, Biber...)') ) def _add_standard_cli_options_index(self): ''' Add standard CLI options in the "index configuration" category. ''' index_group = self._cli_parser.add_argument_group( _T('index optional arguments')) # --defaultist class DefaultistAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.generation.makeindexStyleFilename = self.configuration.get_system_ist_file( ) index_group.add_argument( '--defaultist', action=DefaultistAction, nargs=0, help=_T( 'Allow AutoLaTeX to use MakeIndex with the default style (\'.ist\' file)' )) # --index index_e_group = index_group.add_mutually_exclusive_group() class IndexAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.generation.is_index_enable = True if value: path = genutils.abspath( value, self.configuration.documentDirectory) if os.path.isfile(path): self.configuration.generation.makeindexStyleFilename = path else: logging.error(_T("File not found: %s") % (value)) self.__exiter.exitOnFailure() return index_e_group.add_argument( '--index', action=IndexAction, default=None, nargs='?', metavar=('FILE'), help=_T( 'Allow AutoLaTeX to use MakeIndex. If this option was specified with a value, the FILE value will be assumed to be an \'.ist\' file to pass to MakeIndex' )) # --noindex class NoindexAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.generation.is_index_enable = False index_e_group.add_argument('--noindex', action=NoindexAction, nargs=0, help=_T('Avoid AutoLaTeX to use MakeIndex')) def _add_standard_cli_options_glossary(self): ''' Add standard CLI options in the "glossary configuration" category. ''' glossary_group = self._cli_parser.add_argument_group( _T('glossary optional arguments')) # --glossary # --noglossary # --gloss # --nogloss class GlossaryAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.generation.is_glossary_enable = actionself.const glossary_e_group = glossary_group.add_mutually_exclusive_group() glossary_e_group.add_argument( '--glossary', '--gloss', action=GlossaryAction, const=True, nargs=0, help=_T( 'Enable the call to the glossary tool (makeglossaries...)')) glossary_e_group.add_argument( '--noglossary', '--nogloss', action=GlossaryAction, const=False, nargs=0, help=_T( 'Disable the call to the glossary tool (makeglossaries...)')) def _add_standard_cli_options_warning(self): ''' Add standard CLI options in the "warning configuration" category. ''' warning_cfg_group = self._cli_parser.add_argument_group( _T('warning optional arguments')) # --file-line-warning # --nofile-line-warning class FilelinewarningAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): self.configuration.generation.extendedWarnings = actionself.const warning_group = warning_cfg_group.add_mutually_exclusive_group() warning_group.add_argument( '--file-line-warning', action=FilelinewarningAction, const=True, nargs=0, help=_T( 'Enable the extended format for warnings. This format add the filename and the line number where the warning is occuring, before the warning message by itself' )) warning_group.add_argument( '--nofile-line-warning', action=FilelinewarningAction, const=False, nargs=0, help=_T( 'Disable the extended format for warnings. This format add the filename and the line number where the warning is occuring, before the warning message by itself' )) def _add_standard_cli_options_logging(self): ''' Add standard CLI options in the "logging configuration" category. ''' logging_group = self._cli_parser.add_argument_group( _T('logging optional arguments')) # --debug class DebugAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): logger = logging.getLogger() logger.setLevel(logging.DEBUG) for handler in logger.handlers: handler.setLevel(logging.DEBUG) logging_group.add_argument( '--debug', action=DebugAction, nargs=0, help=_T( 'Run AutoLaTeX in debug mode, i.e., the maximum logging level') ) # --quiet class QuietAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): logger = logging.getLogger() logger.setLevel(logging.ERROR) for handler in logger.handlers: handler.setLevel(logging.ERROR) logging_group.add_argument( '-q', '--quiet', action=QuietAction, nargs=0, help=_T('Run AutoLaTeX without logging except the errors')) # --silent class SilentAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): logger = logging.getLogger() logger.setLevel(LogLevel.OFF) for handler in logger.handlers: handler.setLevel(LogLevel.OFF) logging_group.add_argument( '--silent', action=SilentAction, nargs=0, help=_T( 'Run AutoLaTeX without logging, including no error message')) # --verbose class VerboseAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): logger = logging.getLogger() level = logger.getEffectiveLevel() level = LogLevel.to_lower_level(level) if level < LogLevel.TRACE: # Specific behavior that shows up the configuration self.show_configuration() self.__exiter.exitOnSuccess() else: logger.setLevel(level) for handler in logger.handlers: handler.setLevel(level) logging_group.add_argument( '-v', '--verbose', action=VerboseAction, nargs=0, help=_T( 'Each time this option was specified, AutoLaTeX is more verbose' )) # --Wall class WallAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): logger = logging.getLogger() logger.setLevel(logging.FINE_WARNING) for handler in logger.handlers: handler.setLevel(logging.FINE_WARNING) logging_group.add_argument('--Wall', action=WallAction, nargs=0, help=_T('Show all the warnings')) #--Wnone class WnoneAction(argparse.Action): def __call__(actionself, parser, namespace, value, option_string=None): logger = logging.getLogger() logger.setLevel(logging.ERROR) for handler in logger.handlers: handler.setLevel(logging.ERROR) logging_group.add_argument('--Wnone', action=WnoneAction, nargs=0, help=_T('Show no warning')) def show_configuration(self): ''' Show up the configuration of AutoLaTeX. ''' eprintpkg.epprint(self.configuration) def add_standard_cli_options(self): ''' Add the definition of the standard CLI options. ''' self._add_standard_cli_options_general() self._add_standard_cli_options_path() self._add_standard_cli_options_output() self._add_standard_cli_options_tex() self._add_standard_cli_options_translator() self._add_standard_cli_options_biblio() self._add_standard_cli_options_index() self._add_standard_cli_options_glossary() self._add_standard_cli_options_warning() self._add_standard_cli_options_logging() def add_cli_options(self, parser: object): ''' Add the definition of the application CLI options. :param parser: the CLI parser ''' pass def add_cli_positional_arguments(self, parser: object): ''' Add the definition of the application CLI positional arguments. :param parser: the CLI parser ''' pass def _pre_run_program(self) -> tuple: ''' Run the behavior of the main program before the specific behavior. :return: the tuple with as first element the CLI actions, and the second element the list of unknown arguments. :rtype: tuple (args, list) ''' self.add_standard_cli_options() self.add_cli_options(self._cli_parser) self.add_cli_positional_arguments(self._cli_parser) if not self.configuration.documentDirectory: self.configuration.documentDirectory = os.getcwd() (cmds, unknown_args) = self._parse_command_with_sequence_of_commands() if self.__read_document_configuration: config_file = self._detect_autolatex_configuration_file( self.configuration.documentDirectory) if config_file: config_reader = OldStyleConfigReader() config_reader.readDocumentConfigSafely(config_file, self.configuration) return (cmds, unknown_args) @abstractmethod def _run_program(self, args: object, unknown_args: list): ''' Run the specific behavior. :param args: the CLI arguments that are not consumed by the argparse library. :type args: object :param unknown_args: the list of the unsupported arguments. :type unknown_args: list ''' raise (Exception( "You must implements the _run_program function into the subtype")) def _post_run_program(self, args: object, unknown_args: list): ''' Run the behavior of the main program after the specific behavior. :param args: the CLI arguments that are not consumed by the argparse library. :type args: object :param unknown_args: the list of the unsupported arguments. :type unknown_args: list ''' self.__exiter.exitOnSuccess() def run(self): ''' Run the program. ''' args, unknown_arguments = self._pre_run_program() self._run_program(args, unknown_arguments) self._post_run_program(args, unknown_arguments)