Esempio n. 1
0
    def boot(self):
        """Boot up the experiment, e.g. load config etc."""
        # Load Config/Args for experiment
        if self.config_file:
            try:
                with open(os.path.join(self._path, self.config_file),
                          'r') as cfg:
                    self.config.set(json.load(cfg))
            except Exception as exc:
                print_failure(exc, 2)

        # Load Experiment and testcase repos
        try:
            self.repos['experiment'] = self.app.repositories.get(
                'ExperimentRepository')
            self.repos['testcase'] = self.app.repositories.get(
                'TestCaseRepository')

            self.repos['experiment'] = self.repos['experiment'].from_dict({
                'name':
                self.__class__.__name__.replace('Experiment', ''),
                'start':
                datetime.now(),
                'config_file':
                self.config_file,
                'config_content':
                json.dumps(self.config.all()),
                'tests': []
            })
            self.repos['experiment'].create()
        except Exception as exc:
            print_failure(exc, 2)
Esempio n. 2
0
    def up(self, migration=None):
        """Upgrade to a new migration revision.

        Args:
            migration (Migration, optional): Defaults to None. The Migration Class to upgrade to.

        Raises:
            TypeError: if migration is not a valid migration
        """
        # Select first migration to run
        if migration is None:
            migrated = self._get_migrated_revisions()
            migrations = self.get_migration_files(self.path)
            migration = [mig for mig in migrations if mig[:14] not in migrated]

            if len(migration) == 0:
                print(colored('› Migrations are all up to date.', 'green'))
                return

            migration = self.migrations.get(migration[0])

        # update migration
        try:
            migration.up()
            self._update_revision(migration.revision)
            print(colored('› Migrated', 'green'), colored(migration, 'cyan'))
        except Exception as exc:
            print_failure(
                'Error while ugrading migration {}: {}'.format(migration, exc),
                1)
Esempio n. 3
0
def status(app):
    """List experiment status.

    Args:
        app (App): App Service Container.
    """
    data = []
    headers = [
        colored('Experiment', 'yellow'),
        colored('Config File', 'yellow'),
        colored('Times Executed', 'yellow')
    ]

    try:
        exps = Experiment.get_status(app)
        for experiment in exps.values():
            data.append([
                colored(experiment['name'], 'cyan'),
                colored(experiment.get('config_file'), 'cyan'),
                colored(experiment['count'], 'cyan')
            ])
    except Exception as exc:
        print_failure(exc, 2)

    print(tabulate(data, headers=headers, tablefmt='psql'))
Esempio n. 4
0
    def add_command(self, name, cmd):
        """Add a new command to the parser.

        Args:
            name (str): Name of the command
            cmd (function, AbstractCommand): Command Handler
        """
        if (not isinstance(cmd, types.FunctionType)
                and not issubclass(cmd, AbstractCommand)):
            print_failure(
                "{}-Command must inherit from AbstractCommand!".format(name),
                1)

        # setup command
        cmd = cmd()  # type: AbstractCommand
        command = self._subparsers.add_parser(
            name,
            help=cmd.help,
            description=colored(cmd.description, 'yellow'),
            formatter_class=ColoredHelpFormatter,
            add_help=False)
        command.add_argument('-h',
                             '--help',
                             action='help',
                             default=argparse.SUPPRESS,
                             help='Show this help message and exit.')
        command.titles('Arguments', 'Options', color='cyan')

        # Add arguments and bind command
        for arg, opt in cmd.arguments.items():
            command.add_argument(arg, **opt)
        command.set_defaults(func=cmd.handle)
        self.commands[name] = command
Esempio n. 5
0
    def create(self, name):
        """Create a new plot class instance.

        Args:
            name (str): Name of the plot.

        Returns:
            AbstractPlot: Plot Class
        """
        # Get plot data from config and validate it
        data = self.parse(name)
        config = self.validate(data)

        # Load plot class
        path = self.app.config.get('app.plots.path', 'plots')
        plots = find_files(self.app.root, path, name, '(plot|chart|graph).py')

        if not plots:
            print_failure(
                'Could not find plot named "{}" under path "{}"'.format(
                    name, path),
                exit_code=1)
        plot = load_class(plots[0], path, AbstractPlot)

        # Init plot class
        return plot(self.app.repositories.get('ExperimentRepository'), config,
                    config.get('type', 'plot'))
Esempio n. 6
0
def load_class(src, module, subclass=None):
    """Try to load a class from a module.

    Args:
        src (str): Source file
        module (str): Module name
        subclass (object, optional): Defaults to None. Object the class needs to be derived from

    Returns:
        object: loaded class
    """
    with open(src, 'rb') as filehandler:
        # try to load class from module
        try:
            mod = imp.load_source(module, src, filehandler)
            klass = getattr(mod, os.path.basename(src)[:-3])
        except Exception as exc:
            print_failure('Could not load file: %s' % str(exc), exit_code=2)

        # Check if class is derived from subclass
        if subclass and issubclass(klass, subclass) is False:
            msg = '{} must be derived from the {}.{} class'.format(
                klass.__name__, subclass.__module__, subclass.__name__)
            print_failure(msg, exit_code=3)

        return klass
Esempio n. 7
0
    def down(self, migration=None):
        """Downgrade to an old migration revision.

        Args:
            migration (Migration, optional): Defaults to None. The Migration Class to upgrade to.

        Raises:
            TypeError: if migration is not a valid migration
        """
        # Select first migration to run
        if migration is None:
            # get finished migrations
            migrated = self._get_migrated_revisions()
            migrations = self.get_migration_files(self.path)[::-1]
            migration = [mig for mig in migrations if mig[:14] in migrated]

            if len(migration) == 0:
                print(colored('× There are no migrations to downgrade.',
                              'red'))
                return

            migration = self.migrations.get(migration[0])

        # downgrade migration
        try:
            migration.down()
            self._update_revision(migration.revision, delete=True)
            print(colored('› Migrated', 'green'), colored(migration, 'cyan'))
        except Exception as exc:
            print_failure(
                'Error while downgrading migration {}: {}'.format(
                    migration, exc), 1)
Esempio n. 8
0
    def dispatch(self):
        """Use dispatch pattern to invoke class and let it handle the command."""
        try:
            # dispatch
            options = self._parser.parse_args()

            # only dispatch args if available
            if len(vars(options)) > 1:
                options.func(self.app, options)
            else:
                options.func(self.app)
        except AttributeError:
            # no command selected
            print_failure('Please specify a command')
            self._parser.print_help(sys.stderr)
            sys.exit(2)
Esempio n. 9
0
    def bootstrap(self):
        """Bootstrap the app, i.e. setup config and logger."""
        # Load Config
        loader = Loader(_path_join(self.root, self.config_path), self.config)
        loader.load_config_files()

        # Add experiments and repo folders to path
        paths = [
            self.config.get('app.experiments.path', 'experiments'),
            self.config.get('storage.repositories.path', 'repositories')
        ]
        for path in paths:
            sys.path.insert(0, os.path.abspath(_path_join(self.root, path)))

        # Setup logger
        self._set_logger()
        self.log.info('Bootstrap App')

        # Setup Datastore
        self.log.info('Setup Data Store')
        default_db = {'drivername': 'sqlite', 'database': 'experimentum.db'}
        database = self.config.get('storage.datastore', default_db)

        # Absolute file path based on root for sqlite databases (except in-memory)
        if database['drivername'] == 'sqlite' and database['database'] != '':
            database['database'] = _path_join(self.root, database['database'])

        self.setup_datastore(database)

        if not isinstance(self.store, AbstractStore):
            msg = 'The "{}" Store implementation must implement the AbstractStore interface'
            print_failure(msg.format(self.store.__class__), 1)

        # Load and map Repositories
        self.repositories = RepositoryLoader(self, self.base_repository,
                                             self.store)
        self.repositories.load()

        # Aliases
        self.register_aliases()

        # Register commands
        self.log.info('Register Commands')
        self.cmd_manager = CommandManager(
            self, self.config.get('app.prog', 'app'),
            self.config.get('app.description', ''))
        self._add_commands()
Esempio n. 10
0
    def table(self, name):
        """Create a blueprint for an existing table.

        Args:
            name (str): Name of the table

        Yields:
            Blueprint: New Instance of a table blueprint
        """
        try:
            blueprint = self.app.make('blueprint', name)

            yield blueprint
        except Exception as exc:
            print_failure('Error while creating blueprint: ' + str(exc), 1)

        self._build(blueprint)
Esempio n. 11
0
    def parse(self, plot):
        """Parse the config file for the current plot.

        Args:
            plot (str): Name of the plot.

        Returns:
            object: Config data for the plot
        """
        config = self.app.config.get('plots.{}'.format(plot), None)

        if config is None:
            print_failure('Could not parse config for plot "%s". '
                          'Make sure it exists in the config file!' % plot,
                          exit_code=1)

        return config
    def get(self, repository):
        """Return class of a loaded repository if it exists.

        Args:
            repository (str): Name of repository class.

        Returns:
            AbstractRepository: Repository class
        """
        repo = self._repos.get(repository, None)

        if repo is None:
            print_failure(
                'Could not load repository {}. Are you sure it exists?'.format(
                    repository),
                exit_code=1)

        return repo
def fib(n, seq):
    """Calculate the nth fibonacci number.

    Args:
        n (int)
        seq (list): List of fibonacci numbers

    Returns:
        int
    """
    if n < 0:
        print_failure('Incorrect Input', exit_code=1)
    elif n <= len(seq):
        return seq[n - 1]

    tmp = fib(n - 1, seq) + fib(n - 2, seq)
    seq.append(tmp)
    return tmp
Esempio n. 14
0
    def make(self, alias, *args, **kwargs):
        """Create an instance of an aliased class.

        Args:
            alias (str): Name of class alias.

        Raises:
            Exception: if the alias does not exists.

        Returns:
            object: Instance of the aliased class
        """
        klass = self.aliases.get(alias, None)

        if klass is None:
            print_failure(
                "Class with alias '{}' does not exist.".format(alias), 1)

        return klass(*args, **kwargs)
Esempio n. 15
0
    def save(self, result, iteration):
        """Save the test results in the data store.

        Args:
            result (dict): Result of experiment test run.
            iteration (int): Number of test run iteration.
        """
        data = {
            'experiment_id': self.repos['experiment'].id,
            'iteration': iteration,
            'performances': []
        }
        data.update(result)
        data['performances'].extend(self.performance.export())

        try:
            self.repos['testcase'].from_dict(data).create()
        except Exception as exc:
            for msg in str(exc).split('\n'):
                print_failure(msg)
            raise SystemExit(-1)
    def load(self):
        """Load all repositories from the repo folder and try to map them to the store."""
        # Get Repository files
        files = find_files(
            self.app.root,
            self.app.config.get('storage.repositories.path', 'repositories'))

        for filename in files:
            name = os.path.basename(filename)[:-3]

            # Try to load and map the repos
            try:
                module = self._import_file(
                    name, os.path.abspath(os.path.dirname(filename)))
                repo = getattr(module, name)
                repo.mapping(repo, self.store)
                self._repos[name] = repo

            except Exception as exc:
                print_failure('Could not load repository. ' + str(exc),
                              exit_code=1)
Esempio n. 17
0
    def load(app, path, name):
        """Load and initialize an experiment class.

        Args:
            app (App): Main app calss
            path (str): Path to experiments folder.
            name (str): Name of experiment.

        Returns:
            Experiment: Loaded experiment.
        """
        # Find Experiment Files
        files = find_files(app.root, path, name, remove='experiment.py')
        if not files:
            print_failure(
                'Could not find experiment named "{}" under path "{}"'.format(
                    name, path),
                exit_code=1)

        # Load Experiment class if possible
        experiment = load_class(files[0], 'experiments', Experiment)
        return experiment(app, path)
    def from_dict(cls, data):
        """Create a new Repository instance based on a dictionary entry.

        Args:
            data (dict): Repository Data

        Returns:
            AbstractRepository: Repository instance filled with data.
        """
        init = {}
        relations = {}
        relationships = cls.__relationships__

        for key, val in data.items():
            if key in relationships:
                if isinstance(val, list):
                    relations[key] = [
                        relationships[key][0].from_dict(v) for v in val
                    ]
                else:
                    relations[key] = [relationships[key][0].from_dict(val)]
            else:
                init[key] = val

        try:
            repo = cls(**init)
        except TypeError as err:
            # Unexpected Argument
            if 'unexpected keyword argument' in str(err):
                print_failure(
                    "{}. Either fix the typo or add it the repository constructor."
                    .format(str(err).replace('__init__()', cls.__name__), ), 1)
            # Determine missing parameters
            elif 'required positional argument' in str(
                    err) or 'takes exactly' in str(err):
                import inspect
                if hasattr(inspect, 'getfullargspec'):
                    getargspec = inspect.getfullargspec
                else:
                    getargspec = inspect.getargspec

                available = set(getargspec(cls.__init__).args[1:])
                passed = set(init.keys())
                print_failure(
                    "The {} class is missing the following parameters: {}".
                    format(cls.__name__, available - passed), 2)
            else:
                print_failure(err, -1)

        for key, val in relations.items():
            repo[key] = val

        return repo
Esempio n. 19
0
def test_print_failure_with_exit(capsys):
    with pytest.raises(SystemExit) as pytest_wrapped_e:
        print_failure('My failure message', 2)
    assert 'My failure message' in capsys.readouterr().err
    assert pytest_wrapped_e.type == SystemExit
    assert pytest_wrapped_e.value.code == 2
Esempio n. 20
0
def test_print_failure(capsys):
    print_failure('My failure message')
    assert 'My failure message' in capsys.readouterr().err