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))
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
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
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))
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
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)
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))
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
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)
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!")