Source code for arguments

# -*- coding: utf8 -*-
"""

************************
``helpers/arguments.py``
************************

`BSD`_ © 2018-2019 Science and Technology Facilities Council & contributors

.. _BSD: _static/LICENSE

``arguments.py`` is a helpers module provided to define and configure the argument passing and parsing for the
main modules.


"""
import os
import yaml
import argparse

import customlogging as log
logger = log.config_logger(name=__name__)

import version as my_version
rev = filter(str.isdigit, "$Rev$")  # Do Not Modify this Line
version = my_version.Version(0, 9, 0, svn_rev=rev, disable_svn_logging=True)
__version__ = version.get_version()
__str__ = my_version.about(__name__, __version__, version.revision)


[docs]class Arguments(object): """Creates arguments for passing files and configuration data to the script. A Class which configures and retrieves Arguments for use by a python script. Dictionaries retrieved from YAML files are added as attributes to this class with no sub-processing. Information including the filename of each YAML file parsed is also added as an attribute. See :ref:`arguments` Attributes: config (dict): the parsed dictionary of the ``config.yml`` passed using to script ``--config`` settings (dict): the parsed dictionary of the ``settings.yml`` passed to script using ``--settings`` checkout_enabled (bool): set ``True`` using optional ``--checkout_enabled``, otherwise ``False`` dev_flag (bool): set ``True`` using optional ``--dev``, otherwise ``False`` open_gui (str): Valid values: ``'fpga'``, ``'sim'``. Using optional ``--open_gui``, otherwise ``None`` clean (list of str): Valid values: ``'all'``, ``'fpga'``, ``'ip'``, ``'precompiled_sim'``, ``'sim'``. Using optiona ``clean``, otherwise: ``None`` """ def __init__(self): self.logger = log.config_logger(name=__name__, class_name=self.__class__.__name__) _parser = self._create_parser() self._add_arguments(_parser) args = self._get_args(_parser) for k in vars(args): self.logger.info('Processed Argument: --{arg}' .format(arg=k)) log.sect_break(self.logger) self.logger.info('Loading Arguments from Command Line...') log.sect_break(self.logger) self._import_from_yaml(args) try: self._vunit_args(self.settings, self.settings_file) except AttributeError: self.logger.warning("Settings Missing. Using Default Options for VUnit.") def __repr__(self): return "{self.__class__.__name__}()".format(self=self) def __str__(self): return "{} is a {self.__class__.__name__} object".format(__name__, self=self) @staticmethod def _create_parser(): """ Creates an ``argparse`` object :return: """ return argparse.ArgumentParser() @staticmethod def _add_arguments(parser): """Adds Arguments to provide to python script, using the argparse module. Args: parser (obj): ``argparse`` object Returns: None """ parser.add_argument("--config", dest="config", type=argparse.FileType('r'), default="./config.yml", required=True, help="YAML File Defining Project") parser.add_argument("--settings", dest="settings", type=argparse.FileType('r'), required=True, help="YAML File Defining Settings for Top-Level") parser.add_argument("--checkout_enabled", dest="checkout_disabled", action="store_false", help="Enables Checkout When Creating RepoFlow Objects") parser.add_argument("--dev", dest="dev_flag", action="store_true", help="Development Flag for Executing Script in PyCharm") parser.add_argument("--headless", dest="headless", action="store_true", help="Headless Flag for Forcing GUI Based Options to False. Used to Ensure" "Continuous Integration Environments Execute Unimpeded by " "External User Input") parser.add_argument("--open_gui", dest="open_gui", choices=['fpga', 'sim'], action="store", default=None, help="Opens Project in Specified Tool After Generating Project") parser.add_argument("--clean", dest="clean", choices=['all', 'fpga', 'ip', 'precompiled_sim', 'sim'], nargs="*", action="append", default=None, help="Cleans the Projects Specified Output Prior to Generating Project.") parser.add_argument("--skip_xml2vhdl", dest="skip_xml2vhdl", action="store_true", help="Skips XML2VHDL Regeneration") @staticmethod def _get_args(parser): """Fetches the arguments from a argparse object Args: parser (obj): argparse object Returns: None """ args = parser.parse_args() return args def _import_from_yaml(self, args): """Imports attributes from ``yml`` file. Imports attributes from YAML Files defined by ``_ARG_FILELIST`` which have been passed to via Argument(s) attribute names match the corresponding arg name, and a reference containing the absolute path to the YAML file is also stored in an attribute named ``<arg>_file`` Args: settings (dict): config (dict): returns: None """ for arg in vars(args): attr = getattr(args, arg) if hasattr(attr, 'read'): name_attr = '{}'.format(arg) fname_attr = '{}_file'.format(arg) self.logger.info('Processing: --{}' .format(name_attr)) self.logger.info('Filepath Reference Attribute: {}' .format(fname_attr)) try: abspath = os.path.abspath(attr.name) contents = yaml.load(attr, Loader=yaml.SafeLoader) attr.close() setattr(self, fname_attr, abspath) self.logger.info('Path: {}' .format(abspath)) setattr(self, name_attr, contents) except AttributeError as e: self.logger.error('Error Importing {} YAML File from Argument. File ' '(Probably) Not a YAML File' .format(fname_attr)) self.logger.error('\t{}.' .format(e)) log.errorexit(self.logger) else: self.logger.info('Processing: --{}' .format(arg)) setattr(self, arg, getattr(args, arg)) def _vunit_args(self, settings, settings_file, vunit_args_id='vunit_args', headless=False): """Sets up VUnit Arguments to pass from settings. Replicates the passing of arguments from the command line. Args: settings (dict) Settings retrieved from YAML settings file settings_file (str): Absolute path of settings files used. vunit_args_id (str, optional): Key in settings dict representing VUnit arguments. Default value: ``'vunit_args'`` Returns: None """ supported_vunit_args = ['version', 'log_level', 'output_path', 'test_patterns', 'list', 'files', 'keep_compiling', 'num_threads', 'elaborate', 'verbose', 'xunit_xml', 'coverage', 'unique_sim', 'exit_0', 'no_color', 'dont_catch_exceptions', 'xunit_xml_format', 'export_json', 'with_attributes', 'without_attributes', 'log_level', 'compile', 'quiet', 'fail_fast'] if getattr(self, 'open_gui', list()): if 'sim' in getattr(self, 'open_gui', list()): setattr(self, 'gui', True) else: setattr(self, 'gui', False) else: setattr(self, 'gui', False) clean_flag = False clean_fpga_project = False clean_precompiled_sim = False if getattr(self, 'clean', list()): clean = list() if isinstance(getattr(self, 'clean', list()), list): for c in getattr(self, 'clean', list()): if isinstance(c, list): for cc in c: clean.append(cc) else: clean.append(c) for c in ['all', 'sim']: if c in clean: clean_flag = True break for c in ['all', 'fpga']: if c in clean: clean_fpga_project = True break for c in ['precompiled_sim']: if c in clean: clean_precompiled_sim = True setattr(self, 'clean', clean_flag) setattr(self, 'clean_fpga_project', clean_fpga_project) setattr(self, 'clean_precompiled_sim', clean_precompiled_sim) if vunit_args_id in settings: self.logger.info("Appending VUnit Arguments using '{vunit_args}:' Key from Settings File: {file}" .format(vunit_args=vunit_args_id, file=settings_file)) for key, value in settings[vunit_args_id].items(): if key in supported_vunit_args: self.logger.debug("Setting VUnit Arg: {key}: {value}" .format(key=key, value=value)) if key == 'num_threads' and getattr(self, 'gui'): setattr(self, key, 1) else: setattr(self, key, value) if key == 'version' and value: self.logger.warning("Settings YAML File is Configuring VUnit to Only return Version") elif key == 'list' and value: self.logger.warning("Settings YAML File is Configuring VUnit to Only List Test-Cases") self.logger.warning("\tOnly Test Cases Matching 'test_patterns' are Listed") elif key == 'files' and value: self.logger.warning("Settings YAML File is Configuring VUnit to Only List " "Compile Ordered Files") else: if key == 'clean': self.logger.critical('"vunit_args: {key}" is a Depreciated VUnit Option in Settings ' 'File: {settings}' .format(key=key, settings=settings_file)) self.logger.critical('\tInstead Use Argument: "--clean sim"') elif key == 'clean_precompiled_libs': self.logger.critical('"vunit_args: {key}" is a Depreciated VUnit Option in Settings ' 'File: {settings}' .format(key=key, settings=settings_file)) self.logger.critical('\tInstead Use Argument: "--clean precompiled_sim"') elif key == 'gui': self.logger.critical('"vunit_args: {key}" is a Depreciated VUnit Option in Settings ' 'File: {settings}' .format(key=key, settings=settings_file)) self.logger.critical('\tInstead Use Argument: "--open_gui sim"') else: self.logger.critical('"vunit_args: {key}: {value}" is an Unsupported VUnit Option in ' 'Settings File: {settings}' .format(key=key, value=value, settings=settings_file)) else: self.logger.warning("VUnit Arguments '{vunit_args}' Missing from Settings. " "Using Default Options" .format(vunit_args=vunit_args_id))