Beispiel #1
0
    def _validate_index(self, document):
        """Validate index values of a document

        :raises: :exc:`DuplicateKeyError`: if the document contains unique indexes which are already
        present in the database.
        """
        for index, values in self._indexes.items():
            document_values = document.select({key: 1 for key in index})
            if document_values in values:
                raise DuplicateKeyError(
                    "Duplicate key error: index={} value={}".format(
                        index, document_values))
Beispiel #2
0
    def _decorator(self, *args, **kwargs):

        try:
            rval = method(self, *args, **kwargs)
        except pymongo.errors.DuplicateKeyError as e:
            raise DuplicateKeyError(str(e)) from e
        except pymongo.errors.BulkWriteError as e:
            for error in e.details['writeErrors']:
                if any(m in error["errmsg"] for m in DUPLICATE_KEY_MESSAGES):
                    raise DuplicateKeyError(error["errmsg"]) from e

            raise
        except pymongo.errors.ConnectionFailure as e:
            raise DatabaseError("Connection Failure: database not found on "
                                "specified uri") from e
        except pymongo.errors.OperationFailure as e:
            if any(m in str(e) for m in AUTH_FAILED_MESSAGES):
                raise DatabaseError("Authentication Failure: bad credentials") from e

            raise

        return rval
Beispiel #3
0
    def _decorator(self, *args, **kwargs):

        try:
            rval = method(self, *args, **kwargs)
        except pymongo.errors.ExecutionTimeout as e:
            # Raised when a database operation times out, exceeding the $maxTimeMS set in
            # the query or command option.
            raise DatabaseTimeout() from e
        except pymongo.errors.NetworkTimeout as e:
            # An operation on an open connection exceeded socketTimeoutMS.
            #
            # The remaining connections in the pool stay open. In the case of a
            # write operation, you cannot know whether it succeeded or failed.
            raise DatabaseTimeout() from e
        except pymongo.errors.WTimeoutError as e:
            # Raised when a database operation times out (i.e. wtimeout expires)
            # before replication completes.
            raise DatabaseTimeout() from e
        except pymongo.errors.DuplicateKeyError as e:
            raise DuplicateKeyError(str(e)) from e
        except pymongo.errors.BulkWriteError as e:
            for error in e.details['writeErrors']:
                if any(m in error["errmsg"] for m in DUPLICATE_KEY_MESSAGES):
                    raise DuplicateKeyError(error["errmsg"]) from e

            raise
        except pymongo.errors.ConnectionFailure as e:
            raise DatabaseError("Connection Failure: database not found on "
                                "specified uri") from e
        except pymongo.errors.OperationFailure as e:
            if any(m in str(e) for m in AUTH_FAILED_MESSAGES):
                raise DatabaseError(
                    "Authentication Failure: bad credentials") from e
            elif any(m in str(e) for m in INDEX_OP_ERROR_MESSAGES):
                raise DatabaseError(str(e)) from e
            raise

        return rval
Beispiel #4
0
    def _validate_index(self, document, indexes=None):
        """Validate index values of a document

        :raises: :exc:`DuplicateKeyError`: if the document contains unique indexes which are already
        present in the database.
        """
        if indexes is None:
            indexes = self._indexes.keys()

        for index in indexes:
            document_values = tuple(document[key] for key in index)
            if document_values in self._indexes[index]:
                raise DuplicateKeyError(
                    "Duplicate key error: index={} value={}".format(
                        index, document_values))
Beispiel #5
0
    def create_experiment(self, config):
        """Insert a new experiment inside the database"""
        self._get_project(config['name'])

        self.group = self.backend.new_trial_group(
            TrialGroup(name=experiment_uid(name=config['name'],
                                           version=config['version']),
                       project_id=self.project.uid,
                       metadata=to_json(config)))

        if self.group is None:
            raise DuplicateKeyError('Experiment was already created')

        config['_id'] = self.group.uid
        return config
Beispiel #6
0
    def register_trial(self, trial):
        """Create a new trial to be executed"""
        stamp = datetime.datetime.utcnow()
        trial.submit_time = stamp

        metadata = dict()
        # pylint: disable=protected-access
        metadata["params_types"] = {
            remove_leading_slash(p.name): p.type
            for p in trial._params
        }
        metadata["submit_time"] = to_json(trial.submit_time)
        metadata["end_time"] = to_json(trial.end_time)
        metadata["worker"] = trial.worker
        metadata["metric_types"] = {
            remove_leading_slash(p.name): p.type
            for p in trial.results
        }
        metadata["metric_types"][self.objective] = "objective"
        heartbeat = to_json(trial.heartbeat)
        if heartbeat is None:
            heartbeat = 0
        metadata["heartbeat"] = heartbeat

        metrics = defaultdict(list)
        for p in trial.results:
            metrics[p.name] = [p.value]

        if self.project is None:
            self._get_project(self.group.project_id)

        trial = self.backend.new_trial(
            TrackTrial(
                _hash=trial.hash_name,
                status=get_track_status(trial.status),
                project_id=self.project.uid,
                group_id=self.group.uid,
                parameters=trial.params,
                metadata=metadata,
                metrics=metrics,
            ),
            auto_increment=False,
        )

        if trial is None:
            raise DuplicateKeyError("Was not able to register Trial!")

        return TrialAdapter(trial, objective=self.objective)
Beispiel #7
0
    def _validate_index(self, document, indexes=None):
        """Validate index values of a document

        Raises
        ------
        DuplicateKeyError
            If the document contains unique indexes which are already present in the database.

        """
        if indexes is None:
            indexes = self._indexes.keys()

        for name in indexes:
            keys, data = self._indexes[name]
            document_values = tuple(document[key] for key in keys)
            if document_values in data:
                raise DuplicateKeyError(
                    "Duplicate key error: index={} value={}".format(
                        name, document_values))
Beispiel #8
0
    def register_lie(self, trial):
        """Register a *fake* trial created by the strategist.

        The main difference between fake trial and original ones is the addition of a fake objective
        result, and status being set to completed. The id of the fake trial is different than the id
        of the original trial, but the original id can be computed using the hashcode on parameters
        of the fake trial. See mod:`orion.core.worker.strategy` for more information and the
        Strategist object and generation of fake trials.

        Parameters
        ----------
        trial: `Trial` object
            Fake trial to register in the database

        """
        warnings.warn("Track does not persist lies!")

        if trial.id in self.lies:
            raise DuplicateKeyError("Lie already exists")

        self.lies[trial.id] = trial
        return trial
Beispiel #9
0
    def configure(self, config, enable_branching=True, enable_update=True):
        """Set `Experiment` by overwriting current attributes.

        If `Experiment` was already set and an overwrite is needed, a *branch*
        is advised with a different :attr:`name` for this particular configuration.

        .. note::

            Calling this property is necessary for an experiment's initialization process to be
            considered as done. But it can be called only once.

        """
        if self._init_done:
            raise RuntimeError(
                "Configuration is done; cannot reset an Experiment.")

        # Experiment was build using db, but config was build before experiment got in db.
        # Fake a DuplicateKeyError to force reinstantiation of experiment with proper config.
        if self._id is not None and "datetime" not in config['metadata']:
            raise DuplicateKeyError(
                "Cannot register an existing experiment with a new config")

        # Copy and simulate instantiating given configuration
        experiment = Experiment(self.name)
        experiment._instantiate_config(self.configuration)
        experiment._instantiate_config(config)
        experiment._init_done = True

        # If id is None in this object, then database did not hit a config
        # with same (name, user's name) pair. Everything depends on the user's
        # orion_config to set.
        if self._id is None:
            if config['name'] != self.name or \
                    config['metadata']['user'] != self.metadata['user']:
                raise ValueError(
                    "Configuration given is inconsistent with this Experiment."
                )
            is_new = True
        else:
            # Branch if it is needed
            # TODO: When refactoring experiment managenent, is_different_from
            # will be used when EVC is not available.
            # is_new = self._is_different_from(experiment.configuration)
            branching_configuration = fetch_branching_configuration(config)
            conflicts = detect_conflicts(self.configuration,
                                         experiment.configuration)
            is_new = len(
                conflicts.get()) > 1 or branching_configuration.get('branch')
            if is_new and not enable_branching:
                raise ValueError("Configuration is different and generate a "
                                 "branching event")
            elif is_new:
                experiment._branch_config(conflicts, branching_configuration)

        final_config = experiment.configuration
        self._instantiate_config(final_config)

        self._init_done = True

        if not enable_update:
            return

        # If everything is alright, push new config to database
        if is_new:
            final_config['metadata']['datetime'] = datetime.datetime.utcnow()
            self.metadata['datetime'] = final_config['metadata']['datetime']
            # This will raise DuplicateKeyError if a concurrent experiment with
            # identical (name, metadata.user) is written first in the database.

            self._storage.create_experiment(final_config)

            # XXX: Reminder for future DB implementations:
            # MongoDB, updates an inserted dict with _id, so should you :P
            self._id = final_config['_id']

            # Update refers in db if experiment is root
            if self.refers['parent_id'] is None:
                self.refers['root_id'] = self._id
                self._storage.update_experiment(self, refers=self.refers)

        else:
            # Writing the final config to an already existing experiment raises
            # a DuplicatKeyError because of the embedding id `metadata.user`.
            # To avoid this `final_config["name"]` is popped out before
            # `db.write()`, thus seamingly breaking  the compound index
            # `(name, metadata.user)`
            final_config.pop("name")
            self._storage.update_experiment(self, **final_config)
Beispiel #10
0
    def insert(self, params, results=None, reserve=False):
        """Insert a new trial.

        Experiment must be in writable ('w') or executable ('x') mode.

        Parameters
        ----------
        params: dict
            Parameters of the new trial to add to the database. These parameters
            must comply with the space definition otherwise a ValueError will be raised.
        results: list, optional
            Results to be set for the new trial. Results must have the format
            {name: <str>: type: <'objective', 'constraint' or 'gradient'>, value=<float>} otherwise
            a ValueError will be raised.
            Note that passing results will mark the trial as completed and therefore cannot be
            reserved. The returned trial will have status 'completed'.
            If the results are invalid, the trial will still be inserted but reservation will be
            released.
        reserve: bool, optional
            If reserve=True, the inserted trial will be reserved. `reserve` cannot be True if
            `results` are given.
            Defaults to False.

        Returns
        -------
        `orion.core.worker.trial.Trial`
            The trial inserted in storage. If `reserve=True` and no results are given, the returned
            trial will be in a `reserved` status.

        Raises
        ------
        `ValueError`
            - If results are given and reserve=True
            - If params have invalid format
            - If results have invalid format
        `orion.core.io.database.DuplicateKeyError`
            - If a trial with identical params already exist for the current experiment.
        `orion.core.utils.exceptions.UnsupportedOperation`
            If the experiment was not loaded in writable mode.

        """
        self._check_if_writable()

        if results and reserve:
            raise ValueError(
                "Cannot observe a trial and reserve it. A trial with results has status "
                "`completed` and cannot be reserved.")
        trial = format_trials.dict_to_trial(params, self.space)
        try:
            self._experiment.register_trial(trial, status="reserved")
            self._maintain_reservation(trial)
        except DuplicateKeyError as e:
            message = (
                "A trial with params {} already exist for experiment {}-v{}".
                format(params, self.name, self.version))
            raise DuplicateKeyError(message) from e

        if results:
            try:
                self.observe(trial, results)
            except ValueError:
                self._release_reservation(trial)
                raise

            return trial

        if not reserve:
            self.release(trial)

        return trial
 def register_race_condition(trial):
     raise DuplicateKeyError("Race condition!")