class ProductDesignSpace(Resource['ProductDesignSpace'], DesignSpace): """[ALPHA] An outer product of univariate dimensions, either continuous or enumerated. Parameters ---------- name:str the name of the design space description:str the description of the design space dimensions: list[Dimension] univariate dimensions that are factors of the design space; can be enumerated or continuous """ _response_key = None uid = properties.Optional(properties.UUID, 'id', serializable=False) name = properties.String('config.name') description = properties.Optional(properties.String(), 'config.description') dimensions = properties.List(properties.Object(Dimension), 'config.dimensions') typ = properties.String('config.type', default='Univariate', deserializable=False) status = properties.String('status', serializable=False) status_info = properties.Optional( properties.List(properties.String()), 'status_info', serializable=False ) archived = properties.Boolean('archived', default=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional( properties.List(properties.String()), 'experimental_reasons', serializable=False ) # NOTE: These could go here or in _post_dump - it's unclear which is better right now module_type = properties.String('module_type', default='DESIGN_SPACE') schema_id = properties.UUID('schema_id', default=UUID('6c16d694-d015-42a7-b462-8ef299473c9a')) def __init__(self, name: str, description: str, dimensions: List[Dimension], session: Session = Session()): self.name: str = name self.description: str = description self.dimensions: List[Dimension] = dimensions self.session: Session = session def _post_dump(self, data: dict) -> dict: data['display_name'] = data['config']['name'] return data def __str__(self): return '<ProductDesignSpace {!r}>'.format(self.name)
class AIResourceMetadata(): """Abstract class for representing common metadata for Resources.""" created_by = properties.Optional(properties.UUID, 'created_by', serializable=False) """:Optional[UUID]: id of the user who created the resource""" create_time = properties.Optional(properties.Datetime, 'create_time', serializable=False) """:Optional[datetime]: date and time at which the resource was created""" updated_by = properties.Optional(properties.UUID, 'updated_by', serializable=False) """:Optional[UUID]: id of the user who most recently updated the resource, if it has been updated""" update_time = properties.Optional(properties.Datetime, 'update_time', serializable=False) """:Optional[datetime]: date and time at which the resource was most recently updated, if it has been updated""" archived = properties.Boolean('archived', default=False) """:bool: whether the resource is archived (hidden but not deleted)""" archived_by = properties.Optional(properties.UUID, 'archived_by', serializable=False) """:Optional[UUID]: id of the user who archived the resource, if it has been archived""" archive_time = properties.Optional(properties.Datetime, 'archive_time', serializable=False) """:Optional[datetime]: date and time at which the resource was archived, if it has been archived""" experimental = properties.Boolean("experimental", serializable=False, default=True) """:bool: whether the resource is experimental (newer, less well-tested functionality)""" experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) """:Optional[List[str]]: human-readable reasons why the resource is experimental""" status = properties.Optional(properties.String(), 'status', serializable=False) """:Optional[str]: short description of the resource's status""" status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) """:Optional[List[str]]: human-readable explanations of the status"""
class NthBiggestComponentQuantityColumn( Serializable["NthBiggestComponentQuantityColumn"], Column): """[ALPHA] Quantity of the Nth biggest component. If there are fewer than N components in the composition, then this column will be empty. Parameters ---------- data_source: str name of the variable to use when populating the column n: int index of the component quantity to extract, starting with 1 for the biggest normalize: bool whether to normalize the quantity by the sum of all component amounts. Default is false """ data_source = properties.String('data_source') n = properties.Integer("n") normalize = properties.Boolean("normalize") typ = properties.String('type', default="biggest_component_quantity_column", deserializable=False) def _attrs(self) -> List[str]: return ["data_source", "n", "normalize", "typ"] def __init__(self, *, data_source: str, n: int, normalize: bool = False): self.data_source = data_source self.n = n self.normalize = normalize
class ComponentQuantityColumn(Serializable["ComponentQuantityColumn"], Column): """[ALPHA] Column that extracts the quantity of a given component. If the component is not present in the composition, then the value in the column will be 0.0. Parameters ---------- data_source: str name of the variable to use when populating the column component_name: str name of the component from which to extract the quantity normalize: bool whether to normalize the quantity by the sum of all component amounts. Default is false """ data_source = properties.String('data_source') component_name = properties.String("component_name") normalize = properties.Boolean("normalize") typ = properties.String('type', default="component_quantity_column", deserializable=False) def _attrs(self) -> List[str]: return ["data_source", "component_name", "normalize", "typ"] def __init__(self, *, data_source: str, component_name: str, normalize: bool = False): self.data_source = data_source self.component_name = component_name self.normalize = normalize
class MonteCarloProcessor(Serializable['GridProcessor'], Processor): """[ALPHA] Using a Monte Carlo optimizer to search for the best candidate. The moves that the MonteCarlo optimizer makes are inferred from the descriptors in the design space. Parameters ---------- name: str name of the processor description: str description of the processor """ uid = properties.Optional(properties.UUID, 'id', serializable=False) name = properties.String('config.name') description = properties.Optional(properties.String(), 'config.description') typ = properties.String('config.type', default='ContinuousSearch', deserializable=False) status = properties.String('status', serializable=False) status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) # NOTE: These could go here or in _post_dump - it's unclear which is better right now module_type = properties.String('module_type', default='PROCESSOR') schema_id = properties.UUID( 'schema_id', default=UUID('d8ddfe73-10f7-4456-9de9-9a1638bae403')) def _attrs(self) -> List[str]: return ["name", "description", "typ"] def __init__(self, name: str, description: str, session: Optional[Session] = None): self.name: str = name self.description: str = description self.session: Optional[Session] = session def _post_dump(self, data: dict) -> dict: data['display_name'] = data['config']['name'] return data def __str__(self): return '<MonteCarloProcessor {!r}>'.format(self.name)
class ScalarRangeConstraint(Serializable['ScalarRangeConstraint'], Constraint): """[ALPHA] Represents an inequality constraint on a scalar-valued material attribute. Parameters ---------- descriptor_key: str the key corresponding to a descriptor min: float the minimum value in the range max: float the maximum value in the range min_inclusive: bool if True, will include the min value in the range max_inclusive: bool if True, will include the max value in the range """ descriptor_key = properties.String('descriptor_key') min = properties.Optional(properties.Float, 'min') max = properties.Optional(properties.Float, 'max') min_inclusive = properties.Boolean('min_inclusive') max_inclusive = properties.Boolean('max_inclusive') typ = properties.String('type', default='ScalarRange') def __init__(self, descriptor_key: str, max: Optional[float] = None, min: Optional[float] = None, min_inclusive: Optional[bool] = True, max_inclusive: Optional[bool] = True, session: Optional[Session] = None): self.descriptor_key = descriptor_key self.max = max self.min = min self.min_inclusive = min_inclusive self.max_inclusive = max_inclusive self.session: Optional[Session] = session def __str__(self): return '<ScalarRangeConstraint {!r}>'.format(self.descriptor_key)
class LabelFractionConstraint(Serializable['LabelFractionConstraint'], Constraint): """Represents a constraint on the total amount of ingredients with a given label. Parameters ---------- formulation_descriptor: FormulationDescriptor descriptor to constrain label: str ingredient label to constrain min: float minimum value max: float maximum value is_required: bool, optional whether this ingredient is required. If ``True``, the label must be present and its value must be within the specified range. if ``False``, the label must be within the specified range only if it's present in the formulation, i.e., the value can be 0 or on the range ``[min, max]``. """ formulation_descriptor = properties.Object(FormulationDescriptor, 'formulation_descriptor') label = properties.String('label') min = properties.Optional(properties.Float, 'min') max = properties.Optional(properties.Float, 'max') is_required = properties.Boolean('is_required') typ = properties.String('type', default='LabelFractionConstraint') def __init__(self, *, formulation_descriptor: FormulationDescriptor, label: str, min: float, max: float, is_required: bool = True, session: Optional[Session] = None): self.formulation_descriptor: FormulationDescriptor = formulation_descriptor self.label: str = label self.min: float = min self.max: float = max self.is_required: bool = is_required self.session: Optional[Session] = session def __str__(self): return '<LabelFractionConstraint {!r}::{!r}>'.format( self.formulation_descriptor.key, self.label)
class User(Resource['User']): """ A Citrine User. Parameters ---------- screen_name: str Screen name of the user. email: str Email address of the user. position: str Position of the user. is_admin: bool Whether or not the user is an administrator. session: Session, optional Citrine session used to connect to the database. """ _resource_type = ResourceTypeEnum.USER uid = properties.Optional(properties.UUID, 'id') screen_name = properties.String('screen_name') position = properties.String('position') email = properties.String('email') is_admin = properties.Boolean('is_admin') def __init__(self, screen_name: str, email: str, position: str, is_admin: bool, session: Optional[Session] = None): self.email: str = email self.position: str = position self.screen_name: str = screen_name self.is_admin: bool = is_admin self.session: Optional[Session] = session def __str__(self): return '<User {!r}>'.format(self.screen_name) def get(self): """Retrieve a specific user from the database.""" raise NotImplementedError("Get Not Implemented in Citrine Platform")
class DesignWorkflow(Resource['DesignWorkflow'], Workflow): """[ALPHA] Object that generates scored materials that may approach higher values of the score. Parameters ---------- name: str the name of the workflow design_space_id: UUID the UUID corresponding to the design space to use processor_id: Optional[UUID] the UUID corresponding to the processor to use if none is provided, one matching your design space will be automatically generated predictor_id: UUID the UUID corresponding to the predictor to use project_id: UUID the UUID corresponding to the project to use """ uid = properties.Optional(properties.UUID, 'id', serializable=False) name = properties.String('display_name') status = properties.String('status', serializable=False) status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) archived = properties.Boolean('archived', default=False) created_by = properties.Optional(properties.UUID, 'created_by', serializable=False) create_time = properties.Optional(properties.Datetime, 'create_time', serializable=False) design_space_id = properties.UUID('config.design_space_id') processor_id = properties.Optional(properties.UUID, 'config.processor_id') predictor_id = properties.UUID('config.predictor_id') module_type = properties.String('module_type', default='DESIGN_WORKFLOW') schema_id = properties.UUID( 'schema_id', default=UUID('8af8b007-3e81-4185-82b2-6f62f4a2e6f1')) def __init__(self, name: str, design_space_id: UUID, processor_id: Optional[UUID], predictor_id: UUID, project_id: Optional[UUID] = None, session: Session = Session()): self.name = name self.design_space_id = design_space_id self.processor_id = processor_id self.predictor_id = predictor_id self.project_id = project_id self.session = session def __str__(self): return '<DesignWorkflow {!r}>'.format(self.name) @property def executions(self) -> WorkflowExecutionCollection: """Return a resource representing all visible executions of this workflow.""" if getattr(self, 'project_id', None) is None: raise AttributeError( 'Cannot initialize execution without project reference!') return WorkflowExecutionCollection(self.project_id, self.uid, self.session)
class PerformanceWorkflow(Resource['PerformanceWorkflow'], Workflow): """[ALPHA] Object that executes performance analysis on a given module. Parameters ---------- name: str the name of the workflow analysis: CrossValidationAnalysisConfiguration the configuration object """ uid = properties.Optional(properties.UUID, 'id', serializable=False) name = properties.String('display_name') status = properties.String('status', serializable=False) status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) archived = properties.Boolean('archived', default=False) created_by = properties.Optional(properties.UUID, 'created_by', serializable=False) create_time = properties.Optional(properties.Datetime, 'create_time', serializable=False) analysis = properties.Object(CrossValidationAnalysisConfiguration, 'config.analysis') module_type = properties.String('module_type', default='PERFORMANCE_WORKFLOW') schema_id = properties.UUID( 'schema_id', default=UUID('1d213f0a-d07c-4f70-a4d0-bda3aa951ee0')) typ = properties.String('config.type', default='PerformanceWorkflow', deserializable=False) def __init__(self, name: str, analysis: CrossValidationAnalysisConfiguration, project_id: Optional[UUID] = None, session: Session = Session()): self.name = name self.analysis = analysis self.project_id = project_id self.session = session def __str__(self): return '<PerformanceWorkflow {!r}>'.format(self.name) @property def executions(self) -> WorkflowExecutionCollection: """Return a resource representing all visible executions of this workflow.""" if getattr(self, 'project_id', None) is None: raise AttributeError( 'Cannot initialize execution without project reference!') return WorkflowExecutionCollection(self.project_id, self.uid, self.session)
class MeanPropertyPredictor(Resource['MeanPropertyPredictor'], Predictor, AIResourceMetadata): """A predictor interface that computes mean component properties. .. seealso:: If you are using a deprecated generalized mean property predictor please see :class:`~citrine.informatics.predictors.generalized_mean_property_predictor.GeneralizedMeanPropertyPredictor` for details on how to migrate to the new format. Parameters ---------- name: str name of the configuration description: str description of the predictor input_descriptor: FormulationDescriptor descriptor that represents the input formulation properties: List[RealDescriptor] List of descriptors to featurize p: int Power of the `generalized mean <https://en.wikipedia.org/wiki/Generalized_mean>`_. Only integer powers are supported. impute_properties: bool Whether to impute missing ingredient properties. If ``False`` all ingredients must define values for all featurized properties. Otherwise, the row will not be featurized. If ``True`` and no ``default_properties`` are specified, then the average over the entire dataset is used. If ``True`` and a default is specified in ``default_properties``, then the specified default is used in place of missing values. label: Optional[str] Optional label training_data: Optional[List[DataSource]] Sources of training data. Each can be either a CSV or an GEM Table. Candidates from multiple data sources will be combined into a flattened list and de-duplicated by uid and identifiers. De-duplication is performed if a uid or identifier is shared between two or more rows. The content of a de-duplicated row will contain the union of data across all rows that share the same uid or at least 1 identifier. Training data is unnecessary if the predictor is part of a graph that includes all training data required by this predictor. default_properties: Optional[Mapping[str, float]] Default values to use for imputed properties. Defaults are specified as a map from descriptor key to its default value. If not specified and ``impute_properties == True`` the average over the entire dataset will be used to fill in missing values. Any specified defaults will be used in place of the average over the dataset. ``impute_properties`` must be ``True`` if ``default_properties`` are provided. """ _resource_type = ResourceTypeEnum.MODULE input_descriptor = _properties.Object(FormulationDescriptor, 'config.input') properties = _properties.List(_properties.Object(RealDescriptor), 'config.properties') p = _properties.Integer('config.p') training_data = _properties.List(_properties.Object(DataSource), 'config.training_data') impute_properties = _properties.Boolean('config.impute_properties') default_properties = _properties.Optional( _properties.Mapping(_properties.String, _properties.Float), 'config.default_properties') label = _properties.Optional(_properties.String, 'config.label') typ = _properties.String('config.type', default='MeanProperty', deserializable=False) module_type = _properties.String('module_type', default='PREDICTOR') def __init__(self, name: str, description: str, input_descriptor: FormulationDescriptor, properties: List[RealDescriptor], p: int, impute_properties: bool, default_properties: Optional[Mapping[str, float]] = None, label: Optional[str] = None, training_data: Optional[List[DataSource]] = None, archived: bool = False): self.name: str = name self.description: str = description self.input_descriptor: FormulationDescriptor = input_descriptor self.properties: List[RealDescriptor] = properties self.p: int = p self.training_data: List[DataSource] = self._wrap_training_data( training_data) self.impute_properties: bool = impute_properties self.default_properties: Optional[Mapping[str, float]] = default_properties self.label: Optional[str] = label self.archived: bool = archived def _post_dump(self, data: dict) -> dict: data['display_name'] = data['config']['name'] return data def __str__(self): return '<MeanPropertyPredictor {!r}>'.format(self.name)
class Dataset(Resource['Dataset']): """ A collection of data objects. Datasets are the basic unit of access control. A user with read access to a dataset can view every object in that dataset. A user with write access to a dataset can create, update, and delete objects in the dataset. Parameters ---------- name: str Name of the dataset. Can be used for searching. summary: str A summary of this dataset. description: str Long-form description of the dataset. unique_name: Optional[str] An optional, globally unique name that can be used to retrieve the dataset. Attributes ---------- uid: UUID Unique uuid4 identifier of this dataset. deleted: bool Flag indicating whether or not this dataset has been deleted. created_by: UUID ID of the user who created the dataset. updated_by: UUID ID of the user who last updated the dataset. deleted_by: UUID ID of the user who deleted the dataset, if it is deleted. create_time: int Time the dataset was created, in seconds since epoch. update_time: int Time the dataset was most recently updated, in seconds since epoch. delete_time: int Time the dataset was deleted, in seconds since epoch, if it is deleted. public: bool Flag indicating whether the dataset is publicly readable. """ _response_key = 'dataset' _resource_type = ResourceTypeEnum.DATASET uid = properties.Optional(properties.UUID(), 'id') name = properties.String('name') unique_name = properties.Optional(properties.String(), 'unique_name') summary = properties.String('summary') description = properties.String('description') deleted = properties.Optional(properties.Boolean(), 'deleted') created_by = properties.Optional(properties.UUID(), 'created_by') updated_by = properties.Optional(properties.UUID(), 'updated_by') deleted_by = properties.Optional(properties.UUID(), 'deleted_by') create_time = properties.Optional(properties.Datetime(), 'create_time') update_time = properties.Optional(properties.Datetime(), 'update_time') delete_time = properties.Optional(properties.Datetime(), 'delete_time') public = properties.Optional(properties.Boolean(), 'public') def __init__(self, name: str, summary: str, description: str, unique_name: Optional[str] = None): self.name: str = name self.summary: str = summary self.description: str = description self.unique_name = unique_name # The attributes below should not be set by the user. Instead they will be updated as the # dataset interacts with the backend data service self.uid = None self.deleted = None self.created_by = None self.updated_by = None self.deleted_by = None self.create_time = None self.update_time = None self.delete_time = None self.public = None def __str__(self): return '<Dataset {!r}>'.format(self.name) @property def property_templates(self) -> PropertyTemplateCollection: """Return a resource representing all property templates in this dataset.""" return PropertyTemplateCollection(self.project_id, self.uid, self.session) @property def condition_templates(self) -> ConditionTemplateCollection: """Return a resource representing all condition templates in this dataset.""" return ConditionTemplateCollection(self.project_id, self.uid, self.session) @property def parameter_templates(self) -> ParameterTemplateCollection: """Return a resource representing all parameter templates in this dataset.""" return ParameterTemplateCollection(self.project_id, self.uid, self.session) @property def material_templates(self) -> MaterialTemplateCollection: """Return a resource representing all material templates in this dataset.""" return MaterialTemplateCollection(self.project_id, self.uid, self.session) @property def measurement_templates(self) -> MeasurementTemplateCollection: """Return a resource representing all measurement templates in this dataset.""" return MeasurementTemplateCollection(self.project_id, self.uid, self.session) @property def process_templates(self) -> ProcessTemplateCollection: """Return a resource representing all process templates in this dataset.""" return ProcessTemplateCollection(self.project_id, self.uid, self.session) @property def process_runs(self) -> ProcessRunCollection: """Return a resource representing all process runs in this dataset.""" return ProcessRunCollection(self.project_id, self.uid, self.session) @property def measurement_runs(self) -> MeasurementRunCollection: """Return a resource representing all measurement runs in this dataset.""" return MeasurementRunCollection(self.project_id, self.uid, self.session) @property def material_runs(self) -> MaterialRunCollection: """Return a resource representing all material runs in this dataset.""" return MaterialRunCollection(self.project_id, self.uid, self.session) @property def ingredient_runs(self) -> IngredientRunCollection: """Return a resource representing all ingredient runs in this dataset.""" return IngredientRunCollection(self.project_id, self.uid, self.session) @property def process_specs(self) -> ProcessSpecCollection: """Return a resource representing all process specs in this dataset.""" return ProcessSpecCollection(self.project_id, self.uid, self.session) @property def measurement_specs(self) -> MeasurementSpecCollection: """Return a resource representing all measurement specs in this dataset.""" return MeasurementSpecCollection(self.project_id, self.uid, self.session) @property def material_specs(self) -> MaterialSpecCollection: """Return a resource representing all material specs in this dataset.""" return MaterialSpecCollection(self.project_id, self.uid, self.session) @property def ingredient_specs(self) -> IngredientSpecCollection: """Return a resource representing all ingredient specs in this dataset.""" return IngredientSpecCollection(self.project_id, self.uid, self.session) @property def files(self) -> FileCollection: """Return a resource representing all files in the dataset.""" return FileCollection(self.project_id, self.uid, self.session) def _collection_for(self, data_concepts_resource): if isinstance(data_concepts_resource, MeasurementTemplate): return self.measurement_templates if isinstance(data_concepts_resource, MeasurementSpec): return self.measurement_specs if isinstance(data_concepts_resource, MeasurementRun): return self.measurement_runs if isinstance(data_concepts_resource, MaterialTemplate): return self.material_templates if isinstance(data_concepts_resource, MaterialSpec): return self.material_specs if isinstance(data_concepts_resource, MaterialRun): return self.material_runs if isinstance(data_concepts_resource, ProcessTemplate): return self.process_templates if isinstance(data_concepts_resource, ProcessSpec): return self.process_specs if isinstance(data_concepts_resource, ProcessRun): return self.process_runs if isinstance(data_concepts_resource, IngredientSpec): return self.ingredient_specs if isinstance(data_concepts_resource, IngredientRun): return self.ingredient_runs if isinstance(data_concepts_resource, PropertyTemplate): return self.property_templates if isinstance(data_concepts_resource, ParameterTemplate): return self.parameter_templates if isinstance(data_concepts_resource, ConditionTemplate): return self.condition_templates def register(self, data_concepts_resource: ResourceType, dry_run=False) -> ResourceType: """Register a data concepts resource to the appropriate collection.""" return self._collection_for(data_concepts_resource)\ .register(data_concepts_resource, dry_run=dry_run) def register_all(self, data_concepts_resources: List[ResourceType], dry_run=False) -> List[ResourceType]: """ Register multiple data concepts resources to each of their appropriate collections. Does so in an order that is guaranteed to store all linked items before the item that references them. The uids of the input data concepts resources are updated with their on-platform uids. This supports storing an object that has a reference to an object that doesn't have a uid. Parameters ---------- data_concepts_resources: List[ResourceType] The resources to register. Can be different types. dry_run: bool Whether to actually register the item or run a dry run of the register operation. Dry run is intended to be used for validation. Default: false Returns ------- List[ResourceType] The registered versions """ resources = list() by_type = defaultdict(list) for obj in data_concepts_resources: by_type[obj.typ].append(obj) typ_groups = sorted(list(by_type.values()), key=lambda x: writable_sort_order(x[0])) batch_size = 50 for typ_group in typ_groups: num_batches = len(typ_group) // batch_size for batch_num in range(num_batches + 1): batch = typ_group[batch_num * batch_size:(batch_num + 1) * batch_size] if batch: # final batch is empty when batch_size divides len(typ_group) registered = self._collection_for(batch[0])\ .register_all(batch, dry_run=dry_run) for prewrite, postwrite in zip(batch, registered): if isinstance(postwrite, BaseEntity): prewrite.uids = postwrite.uids resources.extend(registered) return resources def update(self, model: ResourceType) -> ResourceType: """Update a data concepts resource using the appropriate collection.""" return self._collection_for(model).update(model) def delete(self, data_concepts_resource: ResourceType, dry_run=False) -> ResourceType: """Delete a data concepts resource to the appropriate collection.""" uid = next(iter(data_concepts_resource.uids.items()), None) if uid is None: raise ValueError( "Only objects that contain identifiers can be deleted.") return self._collection_for(data_concepts_resource) \ .delete(uid[1], scope=uid[0], dry_run=dry_run) def delete_contents(self, *, timeout: float = 2 * 60, polling_delay: float = 1.0): """ Delete all the GEMD objects from within a single Dataset. Parameters ---------- timeout: float Amount of time to wait on the job (in seconds) before giving up. Note that this number has no effect on the underlying job itself, which can also time out server-side. polling_delay: float How long to delay between each polling retry attempt. Returns ------- List[Tuple[LinkByUID, ApiError]] A list of (LinkByUID, api_error) for each failure to delete an object. Note that this method doesn't raise an exception if an object fails to be deleted. """ path = 'projects/{project_id}/datasets/{dataset_uid}/contents'.format( dataset_uid=self.uid, project_id=self.project_id) response = self.session.delete_resource(path) job_id = response["job_id"] return _poll_for_async_batch_delete_result(self.project_id, self.session, job_id, timeout, polling_delay) def gemd_batch_delete( self, id_list: List[Union[LinkByUID, UUID, str, BaseEntity]], *, timeout: float = 2 * 60, polling_delay: float = 1.0) -> List[Tuple[LinkByUID, ApiError]]: """ Remove a set of GEMD objects. You may provide GEMD objects that reference each other, and the objects will be removed in the appropriate order. A failure will be returned if the object cannot be deleted due to an external reference. All data objects must be associated with this dataset resource. You must also have write access on this dataset. If you wish to delete more than 50 objects, queuing of deletes requires that the types of objects be known, and thus you _must_ provide ids in the form of BaseEntities. Also note that Attribute Templates cannot be deleted at present. Parameters ---------- id_list: List[Union[LinkByUID, UUID, str, BaseEntity]] A list of the IDs of data objects to be removed. They can be passed as a LinkByUID tuple, a UUID, a string, or the object itself. A UUID or string is assumed to be a Citrine ID, whereas a LinkByUID or BaseEntity can also be used to provide an external ID. Returns ------- List[Tuple[LinkByUID, ApiError]] A list of (LinkByUID, api_error) for each failure to delete an object. Note that this method doesn't raise an exception if an object fails to be deleted. """ return _async_gemd_batch_delete(id_list, self.project_id, self.session, self.uid, timeout=timeout, polling_delay=polling_delay)
class PerformanceWorkflow(Resource['PerformanceWorkflow'], Workflow): """[DEPRECATED] Object that executes performance analysis on a given module. Parameters ---------- name: str the name of the workflow analysis: CrossValidationAnalysisConfiguration the configuration object """ name = properties.String('display_name') status = properties.String('status', serializable=False) status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) archived = properties.Boolean('archived', default=False) created_by = properties.Optional(properties.UUID, 'created_by', serializable=False) create_time = properties.Optional(properties.Datetime, 'create_time', serializable=False) analysis = properties.Object(CrossValidationAnalysisConfiguration, 'config.analysis') module_type = properties.String('module_type', default='PERFORMANCE_WORKFLOW') typ = properties.String('config.type', default='PerformanceWorkflow', deserializable=False) def __init__(self, name: str, analysis: CrossValidationAnalysisConfiguration, project_id: Optional[UUID] = None, session: Session = Session()): warn("{this_class} is deprecated. Please use {replacement} instead". format(this_class=self.__class__.name, replacement=PredictorEvaluationWorkflow.__name__), category=DeprecationWarning) self.name = name self.analysis = analysis self.project_id = project_id self.session = session def __str__(self): return '<PerformanceWorkflow {!r}>'.format(self.name) @property def executions(self) -> WorkflowExecutionCollection: """Return a resource representing all visible executions of this workflow.""" if getattr(self, 'project_id', None) is None: raise AttributeError( 'Cannot initialize execution without project reference!') return WorkflowExecutionCollection(self.project_id, self.uid, self.session) def in_progress(self) -> bool: """Whether workflow validation is in progress. Does not query state.""" return self.status == "VALIDATING" or self.status == "CREATED" def succeeded(self) -> bool: """Whether workflow validation has completed successfully. Does not query state.""" return self.status == "READY" def failed(self) -> bool: """Whether workflow validation has completed unsuccessfully. Does not query state.""" return self.status == "INVALID" or self.status == "ERROR"
class Dataset(Resource['Dataset']): """ A collection of data objects. Datasets are the basic unit of access control. A user with read access to a dataset can view every object in that dataset. A user with write access to a dataset can create, update, and delete objects in the dataset. Parameters ---------- name: str Name of the dataset. Can be used for searching. summary: str A summary of this dataset. description: str Long-form description of the dataset. Attributes ---------- uid: UUID Unique uuid4 identifier of this dataset. deleted: bool Flag indicating whether or not this dataset has been deleted. created_by: UUID ID of the user who created the dataset. updated_by: UUID ID of the user who last updated the dataset. deleted_by: UUID ID of the user who deleted the dataset, if it is deleted. create_time: int Time the dataset was created, in seconds since epoch. update_time: int Time the dataset was most recently updated, in seconds since epoch. delete_time: int Time the dataset was deleted, in seconds since epoch, if it is deleted. public: bool Flag indicating whether the dataset is publicly readable. """ _response_key = 'dataset' uid = properties.Optional(properties.UUID(), 'id') name = properties.String('name') summary = properties.String('summary') description = properties.String('description') deleted = properties.Optional(properties.Boolean(), 'deleted') created_by = properties.Optional(properties.UUID(), 'created_by') updated_by = properties.Optional(properties.UUID(), 'updated_by') deleted_by = properties.Optional(properties.UUID(), 'deleted_by') create_time = properties.Optional(properties.Datetime(), 'create_time') update_time = properties.Optional(properties.Datetime(), 'update_time') delete_time = properties.Optional(properties.Datetime(), 'delete_time') public = properties.Optional(properties.Boolean(), 'public') def __init__(self, name: str, summary: str, description: str): self.name: str = name self.summary: str = summary self.description: str = description # The attributes below should not be set by the user. Instead they will be updated as the # dataset interacts with the backend data service self.uid = None self.deleted = None self.created_by = None self.updated_by = None self.deleted_by = None self.create_time = None self.update_time = None self.delete_time = None self.public = None def __str__(self): return '<Dataset {!r}>'.format(self.name) @property def property_templates(self) -> PropertyTemplateCollection: """Return a resource representing all property templates in this dataset.""" return PropertyTemplateCollection(self.project_id, self.uid, self.session) @property def condition_templates(self) -> ConditionTemplateCollection: """Return a resource representing all condition templates in this dataset.""" return ConditionTemplateCollection(self.project_id, self.uid, self.session) @property def parameter_templates(self) -> ParameterTemplateCollection: """Return a resource representing all parameter templates in this dataset.""" return ParameterTemplateCollection(self.project_id, self.uid, self.session) @property def material_templates(self) -> MaterialTemplateCollection: """Return a resource representing all material templates in this dataset.""" return MaterialTemplateCollection(self.project_id, self.uid, self.session) @property def measurement_templates(self) -> MeasurementTemplateCollection: """Return a resource representing all measurement templates in this dataset.""" return MeasurementTemplateCollection(self.project_id, self.uid, self.session) @property def process_templates(self) -> ProcessTemplateCollection: """Return a resource representing all process templates in this dataset.""" return ProcessTemplateCollection(self.project_id, self.uid, self.session) @property def process_runs(self) -> ProcessRunCollection: """Return a resource representing all process runs in this dataset.""" return ProcessRunCollection(self.project_id, self.uid, self.session) @property def measurement_runs(self) -> MeasurementRunCollection: """Return a resource representing all measurement runs in this dataset.""" return MeasurementRunCollection(self.project_id, self.uid, self.session) @property def material_runs(self) -> MaterialRunCollection: """Return a resource representing all material runs in this dataset.""" return MaterialRunCollection(self.project_id, self.uid, self.session) @property def ingredient_runs(self) -> IngredientRunCollection: """Return a resource representing all ingredient runs in this dataset.""" return IngredientRunCollection(self.project_id, self.uid, self.session) @property def process_specs(self) -> ProcessSpecCollection: """Return a resource representing all process specs in this dataset.""" return ProcessSpecCollection(self.project_id, self.uid, self.session) @property def measurement_specs(self) -> MeasurementSpecCollection: """Return a resource representing all measurement specs in this dataset.""" return MeasurementSpecCollection(self.project_id, self.uid, self.session) @property def material_specs(self) -> MaterialSpecCollection: """Return a resource representing all material specs in this dataset.""" return MaterialSpecCollection(self.project_id, self.uid, self.session) @property def ingredient_specs(self) -> IngredientSpecCollection: """Return a resource representing all ingredient specs in this dataset.""" return IngredientSpecCollection(self.project_id, self.uid, self.session) @property def files(self) -> FileCollection: """Return a resource representing all files in the dataset.""" return FileCollection(self.project_id, self.uid, self.session) def _collection_for(self, data_concepts_resource): if isinstance(data_concepts_resource, MeasurementTemplate): return self.measurement_templates if isinstance(data_concepts_resource, MeasurementSpec): return self.measurement_specs if isinstance(data_concepts_resource, MeasurementRun): return self.measurement_runs if isinstance(data_concepts_resource, MaterialTemplate): return self.material_templates if isinstance(data_concepts_resource, MaterialSpec): return self.material_specs if isinstance(data_concepts_resource, MaterialRun): return self.material_runs if isinstance(data_concepts_resource, ProcessTemplate): return self.process_templates if isinstance(data_concepts_resource, ProcessSpec): return self.process_specs if isinstance(data_concepts_resource, ProcessRun): return self.process_runs if isinstance(data_concepts_resource, IngredientSpec): return self.ingredient_specs if isinstance(data_concepts_resource, IngredientRun): return self.ingredient_runs if isinstance(data_concepts_resource, PropertyTemplate): return self.property_templates if isinstance(data_concepts_resource, ParameterTemplate): return self.parameter_templates if isinstance(data_concepts_resource, ConditionTemplate): return self.condition_templates def register(self, data_concepts_resource: ResourceType, dry_run=False) -> ResourceType: """Register a data concepts resource to the appropriate collection.""" return self._collection_for(data_concepts_resource)\ .register(data_concepts_resource, dry_run=dry_run) def register_all(self, data_concepts_resources: List[ResourceType], dry_run=False) -> List[ResourceType]: """ Register multiple data concepts resources to each of their appropriate collections. Does so in an order that is guaranteed to store all linked items before the item that references them. The uids of the input data concepts resources are updated with their on-platform uids. This supports storing an object that has a reference to an object that doesn't have a uid. Parameters ---------- data_concepts_resources: List[ResourceType] The resources to register. Can be different types. dry_run: bool Whether to actually register the item or run a dry run of the register operation. Dry run is intended to be used for validation. Default: false Returns ------- List[ResourceType] The registered versions """ resources = list() by_type = defaultdict(list) for obj in data_concepts_resources: by_type[obj.typ].append(obj) typ_groups = sorted(list(by_type.values()), key=lambda x: writable_sort_order(x[0])) batch_size = 50 for typ_group in typ_groups: num_batches = len(typ_group) // batch_size for batch_num in range(num_batches + 1): batch = typ_group[batch_num * batch_size: (batch_num + 1) * batch_size] if batch: # final batch is empty when batch_size divides len(typ_group) registered = self._collection_for(batch[0])\ .register_all(batch, dry_run=dry_run) for prewrite, postwrite in zip(batch, registered): if isinstance(postwrite, BaseEntity): prewrite.uids = postwrite.uids resources.extend(registered) return resources def delete(self, data_concepts_resource: ResourceType, dry_run=False) -> ResourceType: """Delete a data concepts resource to the appropriate collection.""" uid = next(iter(data_concepts_resource.uids.items()), None) if uid is None: raise ValueError("Only objects that contain identifiers can be deleted.") return self._collection_for(data_concepts_resource) \ .delete(uid[1], scope=uid[0], dry_run=dry_run)
class ScalarRangeConstraint(Serializable['ScalarRangeConstraint'], Constraint): """Represents an inequality constraint on a scalar-valued material attribute. Parameters ---------- descriptor_key: str the key corresponding to a descriptor lower_bound: float the minimum value in the range upper_bound: float the maximum value in the range lower_inclusive: bool if True, will include the lower bound value in the range (default: true) upper_inclusive: bool if True, will include the max value in the range (default: true) """ descriptor_key = properties.String('descriptor_key') lower_bound = properties.Optional(properties.Float, 'min') upper_bound = properties.Optional(properties.Float, 'max') lower_inclusive = properties.Boolean('min_inclusive') upper_inclusive = properties.Boolean('max_inclusive') typ = properties.String('type', default='ScalarRange') def __init__(self, descriptor_key: str, lower_bound: Optional[float] = None, upper_bound: Optional[float] = None, lower_inclusive: Optional[bool] = None, upper_inclusive: Optional[bool] = None, min: Optional[float] = None, max: Optional[float] = None, min_inclusive: Optional[bool] = None, max_inclusive: Optional[bool] = None, session: Optional[Session] = None): if lower_bound is not None and min is not None: raise ValueError("Both lower_bound and min were specified. " "Please only specify lower_bound.") if upper_bound is not None and max is not None: raise ValueError("Both upper_bound and max were specified. " "Please only specify upper_bound.") if lower_inclusive is not None and min_inclusive is not None: raise ValueError( "Both lower_inclusive and min_inclusive were specified. " "Please only specify lower_inclusive.") if upper_inclusive is not None and max_inclusive is not None: raise ValueError( "Both upper_inclusive and max_inclusive were specified. " "Please only specify upper_inclusive.") if min is not None or max is not None: msg = "The min/max arguments for ScalarRangeConstraint are deprecated. " \ "Please use lower_bound/upper_bound instead." warn(msg, DeprecationWarning) if min_inclusive is not None or max_inclusive is not None: msg = "The min_inclusive/max_inclusive arguments for ScalarRangeConstraint " \ "are deprecated. " \ "Please use lower_inclusive/upper_inclusive instead." warn(msg, DeprecationWarning) self.descriptor_key = descriptor_key if lower_bound is not None: self.lower_bound = lower_bound else: self.lower_bound = min if upper_bound is not None: self.upper_bound = upper_bound else: self.upper_bound = max # we have to be careful with None and boolean values # None or False or True -> True, so that pattern doesn't work self.lower_inclusive = True if lower_inclusive is not None: self.lower_inclusive = lower_inclusive elif min_inclusive is not None: self.lower_inclusive = min_inclusive self.upper_inclusive = True if upper_inclusive is not None: self.upper_inclusive = upper_inclusive elif max_inclusive is not None: self.upper_inclusive = max_inclusive self.session: Optional[Session] = session def __str__(self): return '<ScalarRangeConstraint {!r}>'.format(self.descriptor_key) @property def min(self): """[DEPRECATED] Alias for lower_bound.""" warn( "ScalarRangeConstraint.min is deprecated. Please use lower_bound instead", DeprecationWarning) return self.lower_bound @property def max(self): """[DEPRECATED] Alias for upper_bound.""" warn( "ScalarRangeConstraint.max is deprecated. Please use upper_bound instead", DeprecationWarning) return self.upper_bound @property def min_inclusive(self): """[DEPRECATED] Alias for lower_inclusive.""" warn( "ScalarRangeConstraint.min_inclusive is deprecated. " "Please use lower_inclusive instead", DeprecationWarning) return self.lower_inclusive @property def max_inclusive(self): """[DEPRECATED] Alias for upper_inclusive.""" warn( "ScalarRangeConstraint.max_inclusive is deprecated. " "Please use upper_inclusive instead", DeprecationWarning) return self.upper_inclusive
class Dataset(Resource['Dataset']): """ A collection of data objects. Datasets are the basic unit of access control. A user with read access to a dataset can view every object in that dataset. A user with write access to a dataset can create, update, and delete objects in the dataset. Parameters ---------- name: str Name of the dataset. Can be used for searching. summary: str A summary of this dataset. description: str Long-form description of the dataset. Attributes ---------- uid: UUID Unique uuid4 identifier of this dataset. deleted: bool Flag indicating whether or not this dataset has been deleted. created_by: UUID ID of the user who created the dataset. updated_by: UUID ID of the user who last updated the dataset. deleted_by: UUID ID of the user who deleted the dataset, if it is deleted. create_time: int Time the dataset was created, in seconds since epoch. update_time: int Time the dataset was most recently updated, in seconds since epoch. delete_time: int Time the dataset was deleted, in seconds since epoch, if it is deleted. """ _response_key = 'dataset' uid = properties.Optional(properties.UUID(), 'id') name = properties.String('name') summary = properties.String('summary') description = properties.String('description') deleted = properties.Optional(properties.Boolean(), 'deleted') created_by = properties.Optional(properties.UUID(), 'created_by') updated_by = properties.Optional(properties.UUID(), 'updated_by') deleted_by = properties.Optional(properties.UUID(), 'deleted_by') create_time = properties.Optional(properties.Datetime(), 'create_time') update_time = properties.Optional(properties.Datetime(), 'update_time') delete_time = properties.Optional(properties.Datetime(), 'delete_time') def __init__(self, name: str, summary: str, description: str): self.name: str = name self.summary: str = summary self.description: str = description # The attributes below should not be set by the user. Instead they will be updated as the # dataset interacts with the backend data service self.uid = None self.deleted = None self.created_by = None self.updated_by = None self.deleted_by = None self.create_time = None self.update_time = None self.delete_time = None def __str__(self): return '<Dataset {!r}>'.format(self.name) @property def property_templates(self) -> PropertyTemplateCollection: """Return a resource representing all property templates in this dataset.""" return PropertyTemplateCollection(self.project_id, self.uid, self.session) @property def condition_templates(self) -> ConditionTemplateCollection: """Return a resource representing all condition templates in this dataset.""" return ConditionTemplateCollection(self.project_id, self.uid, self.session) @property def parameter_templates(self) -> ParameterTemplateCollection: """Return a resource representing all parameter templates in this dataset.""" return ParameterTemplateCollection(self.project_id, self.uid, self.session) @property def material_templates(self) -> MaterialTemplateCollection: """Return a resource representing all material templates in this dataset.""" return MaterialTemplateCollection(self.project_id, self.uid, self.session) @property def measurement_templates(self) -> MeasurementTemplateCollection: """Return a resource representing all measurement templates in this dataset.""" return MeasurementTemplateCollection(self.project_id, self.uid, self.session) @property def process_templates(self) -> ProcessTemplateCollection: """Return a resource representing all process templates in this dataset.""" return ProcessTemplateCollection(self.project_id, self.uid, self.session) @property def process_runs(self) -> ProcessRunCollection: """Return a resource representing all process runs in this dataset.""" return ProcessRunCollection(self.project_id, self.uid, self.session) @property def measurement_runs(self) -> MeasurementRunCollection: """Return a resource representing all measurement runs in this dataset.""" return MeasurementRunCollection(self.project_id, self.uid, self.session) @property def material_runs(self) -> MaterialRunCollection: """Return a resource representing all material runs in this dataset.""" return MaterialRunCollection(self.project_id, self.uid, self.session) @property def ingredient_runs(self) -> IngredientRunCollection: """Return a resource representing all ingredient runs in this dataset.""" return IngredientRunCollection(self.project_id, self.uid, self.session) @property def process_specs(self) -> ProcessSpecCollection: """Return a resource representing all process specs in this dataset.""" return ProcessSpecCollection(self.project_id, self.uid, self.session) @property def measurement_specs(self) -> MeasurementSpecCollection: """Return a resource representing all measurement specs in this dataset.""" return MeasurementSpecCollection(self.project_id, self.uid, self.session) @property def material_specs(self) -> MaterialSpecCollection: """Return a resource representing all material specs in this dataset.""" return MaterialSpecCollection(self.project_id, self.uid, self.session) @property def ingredient_specs(self) -> IngredientSpecCollection: """Return a resource representing all ingredient specs in this dataset.""" return IngredientSpecCollection(self.project_id, self.uid, self.session) @property def files(self) -> FileCollection: """Return a resource representing all files in the dataset.""" return FileCollection(self.project_id, self.uid, self.session)
class EnumeratedProcessor(Serializable['EnumeratedProcessor'], Processor): """[ALPHA] Process a design space by enumerating up to a fixed number of samples from the domain. Each sample is processed independently. Parameters ---------- name: str name of the processor description: str description of the processor max_size: int maximum number of samples that can be enumerated over """ uid = properties.Optional(properties.UUID, 'id', serializable=False) name = properties.String('config.name') description = properties.Optional(properties.String(), 'config.description') max_size = properties.Integer('config.max_size') typ = properties.String('config.type', default='Enumerated', deserializable=False) status = properties.String('status', serializable=False) status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) archived = properties.Boolean('archived', default=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) # NOTE: These could go here or in _post_dump - it's unclear which is better right now module_type = properties.String('module_type', default='PROCESSOR') schema_id = properties.UUID( 'schema_id', default=UUID('307b88a2-fd50-4d27-ae91-b8d6282f68f7')) def _attrs(self) -> List[str]: return ["name", "description", "max_size", "typ"] def __init__(self, name: str, description: str, max_size: Optional[int] = None, session: Optional[Session] = None): self.name: str = name self.description: str = description self.max_size: int = max_size or 2**31 - 1 # = 2147483647 (max 32-bit integer) self.session: Optional[Session] = session def _post_dump(self, data: dict) -> dict: data['display_name'] = data['config']['name'] return data def __str__(self): return '<EnumeratedProcessor {!r}>'.format(self.name)
class EnumeratedDesignSpace(Resource['EnumeratedDesignSpace'], DesignSpace): """[ALPHA] An explicit enumeration of candidate materials to score. Note that every candidate must have exactly the descriptors in the list populated (no more, no less) in order to be included. Parameters ---------- name:str the name of the design space description:str the description of the design space descriptors: list[Descriptor] the list of descriptors included in the candidates of the design space data: list[dict] list of dicts of the shape `{<descriptor_key>: <descriptor_value>}` where each dict corresponds to a candidate in the design space """ _response_key = None uid = properties.Optional(properties.UUID, 'id', serializable=False) name = properties.String('config.name') description = properties.Optional(properties.String(), 'config.description') descriptors = properties.List(properties.Object(Descriptor), 'config.descriptors') data = properties.List(properties.Mapping(properties.String, properties.Raw), 'config.data') typ = properties.String('config.type', default='EnumeratedDesignSpace', deserializable=False) status = properties.String('status', serializable=False) status_info = properties.Optional( properties.List(properties.String()), 'status_info', serializable=False ) archived = properties.Boolean('archived', default=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional( properties.List(properties.String()), 'experimental_reasons', serializable=False ) # NOTE: These could go here or in _post_dump - it's unclear which is better right now module_type = properties.String('module_type', default='DESIGN_SPACE') schema_id = properties.UUID('schema_id', default=UUID('f3907a58-aa46-462c-8837-a5aa9605e79e')) def __init__(self, name: str, description: str, descriptors: List[Descriptor], data: List[Mapping[str, Any]], session: Session = Session()): self.name: str = name self.description: str = description self.descriptors: List[Descriptor] = descriptors self.data: List[Mapping[str, Any]] = data self.session: Session = session def _post_dump(self, data: dict) -> dict: data['display_name'] = data['config']['name'] return data def __str__(self): return '<EnumeratedDesignSpace {!r}>'.format(self.name)
class GridProcessor(Serializable['GridProcessor'], Processor): """[ALPHA] Generates samples from the outer product of finite dimensions, then scans over them. To create a finite set of materials from continuous dimensions, a uniform grid is created between the lower and upper bounds of the descriptor. The number of points along each dimension is specified by `grid_sizes`. Parameters ---------- name: str name of the processor description: str description of the processor grid_sizes: dict[str, int] the number of points to select along each dimension of the grid, by dimension name """ uid = properties.Optional(properties.UUID, 'id', serializable=False) name = properties.String('config.name') description = properties.Optional(properties.String(), 'config.description') typ = properties.String('config.type', default='Grid', deserializable=False) grid_sizes = properties.Mapping(properties.String, properties.Integer, 'config.grid_dimensions') status = properties.String('status', serializable=False) status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) archived = properties.Boolean('archived', default=False) experimental = properties.Boolean("experimental", serializable=False, default=True) experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) # NOTE: These could go here or in _post_dump - it's unclear which is better right now module_type = properties.String('module_type', default='PROCESSOR') schema_id = properties.UUID( 'schema_id', default=UUID('272791a5-5468-4344-ac9f-2811d9266a4d')) def _attrs(self) -> List[str]: return ["name", "description", "grid_sizes", "typ"] def __init__(self, name: str, description: str, grid_sizes: Mapping[str, int], session: Optional[Session] = None): self.name: str = name self.description: str = description self.grid_sizes: Mapping[str, int] = grid_sizes self.session: Optional[Session] = session def _post_dump(self, data: dict) -> dict: data['display_name'] = data['config']['name'] return data def __str__(self): return '<GridProcessor {!r}>'.format(self.name)
class DesignExecution(Resource['DesignExecution'], Pageable, AsynchronousObject): """The execution of a DesignWorkflow. Possible statuses are INPROGRESS, SUCCEEDED, and FAILED. Design executions also have a ``status_description`` field with more information. Parameters ---------- project_id: str Unique identifier of the project that contains the workflow execution """ _paginator: Paginator = Paginator() _collection_key = 'response' uid: UUID = properties.UUID('id', serializable=False) """:UUID: Unique identifier of the workflow execution""" workflow_id = properties.UUID('workflow_id', serializable=False) """:UUID: Unique identifier of the workflow that was executed""" version_number = properties.Integer("version_number", serializable=False) """:int: Integer identifier that increases each time the workflow is executed. The first execution has version_number = 1.""" status = properties.Optional(properties.String(), 'status', serializable=False) """:Optional[str]: short description of the execution's status""" status_description = properties.Optional(properties.String(), 'status_description', serializable=False) """:Optional[str]: more detailed description of the execution's status""" status_info = properties.Optional(properties.List(properties.String()), 'status_info', serializable=False) """:Optional[List[str]]: human-readable explanations of the status""" experimental = properties.Boolean("experimental", serializable=False, default=True) """:bool: whether the execution is experimental (newer, less well-tested functionality)""" experimental_reasons = properties.Optional(properties.List( properties.String()), 'experimental_reasons', serializable=False) """:Optional[List[str]]: human-readable reasons why the execution is experimental""" created_by = properties.Optional(properties.UUID, 'created_by', serializable=False) """:Optional[UUID]: id of the user who created the resource""" updated_by = properties.Optional(properties.UUID, 'updated_by', serializable=False) """:Optional[UUID]: id of the user who most recently updated the resource, if it has been updated""" create_time = properties.Optional(properties.Datetime, 'create_time', serializable=False) """:Optional[datetime]: date and time at which the resource was created""" update_time = properties.Optional(properties.Datetime, 'update_time', serializable=False) """:Optional[datetime]: date and time at which the resource was most recently updated, if it has been updated""" score = properties.Object(Score, 'score') """:Score: score by which this execution was evaluated""" descriptors = properties.List(properties.Object(Descriptor), 'descriptors') """:List[Descriptor]: all of the descriptors in the candidates generated by this execution""" def __init__(self): """This shouldn't be called, but it defines members that are set elsewhere.""" self.project_id: Optional[UUID] = None # pragma: no cover self.session: Optional[Session] = None # pragma: no cover def __str__(self): return '<DesignExecution {!r}>'.format(str(self.uid)) def _path(self): return '/projects/{project_id}/design-workflows/{workflow_id}/executions/{execution_id}' \ .format(project_id=self.project_id, workflow_id=self.workflow_id, execution_id=self.uid) def in_progress(self) -> bool: """Whether design execution is in progress. Does not query state.""" return self.status == "INPROGRESS" def succeeded(self) -> bool: """Whether design execution has completed successfully. Does not query state.""" return self.status == "SUCCEEDED" def failed(self) -> bool: """Whether design execution has completed unsuccessfully. Does not query state.""" return self.status == "FAILED" @classmethod def _build_candidates( cls, subset_collection: Iterable[dict]) -> Iterable[DesignCandidate]: for candidate in subset_collection: yield DesignCandidate.build(candidate) def candidates( self, page: Optional[int] = None, per_page: int = 100, ) -> Iterable[DesignCandidate]: """Fetch the Design Candidates for the particular execution, paginated.""" path = self._path() + '/candidates' fetcher = partial(self._fetch_page, path=path) return self._paginator.paginate( page_fetcher=fetcher, collection_builder=self._build_candidates, page=page, per_page=per_page)