diff --git a/docs/source/workflows/data_sources.rst b/docs/source/workflows/data_sources.rst index 210f1f5d5..b4f521145 100644 --- a/docs/source/workflows/data_sources.rst +++ b/docs/source/workflows/data_sources.rst @@ -48,32 +48,3 @@ The example below assumes that the uuid and the version of the desired GEM Table Note that the descriptor keys above are the headers of the *variable* not the column in the table. The last term in the column header is a suffix associated with the specific column definition rather than the variable. It should be omitted from the descriptor key. - -Experiment Data Source ----------------------- - -An :class:`~citrine.resources.experiment_datasource.ExperimentDataSource` references a snapshot of the Experiment Results in a Branch that are fit for training. -This snapshot is created when one updates the data on a Branch and chooses to include Experiment Results in the training data via the web application. -There is only one Experiment Data Source per Branch, though it is versioned. -The version increments everytime a new or updated Experiment Result is chosen as training data via the web application. - -One can reference an Experiment Data Source from a branch: - -.. code:: python - - eds = branch.experiment_datasource - -The `.read()` method will return a string in a CSV-friendly format for convenient export or further analysis: - -.. code:: python - - # Write to CSV: - with open('experiment_datasource.csv', 'w') as f: - f.write(eds.read()) - - # Convert to a Pandas DataFrame - import pandas as pd - from io import StringIO - - eds_io = StringIO(eds.read()) - eds_dataframe = pd.read_csv(eds_io.read())) diff --git a/src/citrine/__version__.py b/src/citrine/__version__.py index 111dc9172..ba7be38e4 100644 --- a/src/citrine/__version__.py +++ b/src/citrine/__version__.py @@ -1 +1 @@ -__version__ = "4.3.0" +__version__ = "5.0.0" diff --git a/src/citrine/informatics/constraints/ingredient_ratio_constraint.py b/src/citrine/informatics/constraints/ingredient_ratio_constraint.py index 9d7683699..d0dbaabd0 100644 --- a/src/citrine/informatics/constraints/ingredient_ratio_constraint.py +++ b/src/citrine/informatics/constraints/ingredient_ratio_constraint.py @@ -49,7 +49,7 @@ class IngredientRatioConstraint(Serializable['IngredientRatioConstraint'], Const # The backend provides basis ingredients and basis labels as a dictionary from the key to a # multiplier. However, for ingredient ratio constraints, the multiplier in the denominator # should always be one, so we can't allow users to enter it. We need to use properties for this - # behavior. It also allows us to display deprecation warnings for the coming type change. + # behavior. _basis_ingredients = properties.Mapping( properties.String, properties.Float, 'basis_ingredients', default={}) _basis_labels = properties.Mapping( diff --git a/src/citrine/informatics/data_sources.py b/src/citrine/informatics/data_sources.py index 9d26ffe75..f9cf1d927 100644 --- a/src/citrine/informatics/data_sources.py +++ b/src/citrine/informatics/data_sources.py @@ -2,8 +2,6 @@ from abc import abstractmethod from uuid import UUID -from deprecation import deprecated - from citrine._serialization import properties from citrine._serialization.polymorphic_serializable import PolymorphicSerializable from citrine._serialization.serializable import Serializable @@ -12,7 +10,6 @@ __all__ = [ 'DataSource', 'GemTableDataSource', - 'ExperimentDataSourceRef', 'SnapshotDataSource', ] @@ -33,7 +30,7 @@ def __eq__(self, other): @classmethod def _subclass_list(self) -> list[type[Serializable]]: - return [GemTableDataSource, ExperimentDataSourceRef, SnapshotDataSource] + return [GemTableDataSource, SnapshotDataSource] @classmethod def get_type(cls, data) -> type[Serializable]: @@ -116,37 +113,6 @@ def from_gemtable(cls, table: GemTable) -> "GemTableDataSource": return GemTableDataSource(table_id=table.uid, table_version=table.version) -class ExperimentDataSourceRef(Serializable['ExperimentDataSourceRef'], DataSource): - """[DEPRECATED] A reference to a data source based on an experiment result on the platform. - - Parameters - ---------- - datasource_id: UUID - Unique identifier for the Experiment Data Source - - """ - - typ = properties.String('type', default='experiments_data_source', deserializable=False) - datasource_id = properties.UUID("datasource_id") - - _data_source_type = "experiments" - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates on the platform. " - "Alternatively, you may convert the candidate into a collection of GEMD " - "objects manually.") - def __init__(self, *, datasource_id: UUID): - self.datasource_id: UUID = datasource_id - - @classmethod - def _data_source_id_builder(cls, *args) -> DataSource: - return ExperimentDataSourceRef(datasource_id=UUID(args[0])) - - def to_data_source_id(self) -> str: - """Generate the data_source_id for this DataSource.""" - return f"{self._data_source_type}::{self.datasource_id}" - - class SnapshotDataSource(Serializable['SnapshotDataSource'], DataSource): """A reference to a data source based on a Snapshot on the data platform. diff --git a/src/citrine/informatics/experiment_values.py b/src/citrine/informatics/experiment_values.py deleted file mode 100644 index e78f7b8b7..000000000 --- a/src/citrine/informatics/experiment_values.py +++ /dev/null @@ -1,149 +0,0 @@ -from deprecation import deprecated - -from citrine._serialization.serializable import Serializable -from citrine._serialization.polymorphic_serializable import PolymorphicSerializable -from citrine._serialization import properties - -__all__ = [ - 'ExperimentValue', - 'RealExperimentValue', - 'IntegerExperimentValue', - 'CategoricalExperimentValue', - 'MixtureExperimentValue', - 'ChemicalFormulaExperimentValue', - 'MolecularStructureExperimentValue' -] - - -class ExperimentValue(PolymorphicSerializable['ExperimentValue']): - """[DEPRECATED] An container for experiment values. - - Abstract type that returns the proper type given a serialized dict. - """ - - @classmethod - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def build(cls, data: dict) -> 'ExperimentValue': - """Build the underlying type.""" - return super().build(data) - - @classmethod - def get_type(cls, data) -> type[Serializable]: - """Return the subtype.""" - return { - "RealValue": RealExperimentValue, - "IntegerValue": IntegerExperimentValue, - "CategoricalValue": CategoricalExperimentValue, - "MixtureValue": MixtureExperimentValue, - "InorganicValue": ChemicalFormulaExperimentValue, - "OrganicValue": MolecularStructureExperimentValue, - }[data["type"]] - - def __str__(self): - return f"<{self.__class__.__name__} {self.value!r}>" - - def __repr__(self): - return f"{self.__class__.__name__}({self.value})" - - def __eq__(self, other): - return self._equals(other, ["value", "typ"]) - - def _equals(self, other, attrs) -> bool: - """Check to see if the attrs from the other instance match this instance. - - Returns True if all of the attribute names from attrs match between this and - the other instance, else False. A missing attribute from this instance will - raise an AttributeError, and False if missing from the other instance. - - Parameters - ---------- - other: Description - the Description instance to compare to - attrs: list[str] - A list of attribute names to lookup and compare - - """ - # Check that all attrs exist on this object and raise an AttributeError if not. - [self.__getattribute__(key) for key in attrs] - - try: - return all([ - self.__getattribute__(key) == other.__getattribute__(key) for key in attrs - ]) - except AttributeError: - return False - - -class RealExperimentValue(Serializable['RealExperimentValue'], ExperimentValue): - """[DEPRECATED] A floating point experiment result.""" - - value = properties.Float('value') - typ = properties.String('type', default='RealValue', deserializable=False) - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, value: float): - self.value = value - - -class IntegerExperimentValue(Serializable['IntegerExperimentValue'], ExperimentValue): - """[DEPRECATED] An integer value experiment result.""" - - value = properties.Integer('value') - typ = properties.String('type', default='IntegerValue', deserializable=False) - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, value: int): - self.value = value - - -class CategoricalExperimentValue(Serializable['CategoricalExperimentValue'], ExperimentValue): - """[DEPRECATED] An experiment result with a categorical value.""" - - value = properties.String('value') - typ = properties.String('type', default='CategoricalValue', deserializable=False) - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, value: str): - self.value = value - - -class MixtureExperimentValue(Serializable['MixtureExperimentValue'], ExperimentValue): - """[DEPRECATED] An experiment result mapping ingredients and labels to real values.""" - - value = properties.Mapping(properties.String, properties.Float, 'value') - typ = properties.String('type', default='MixtureValue', deserializable=False) - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, value: dict[str, float]): - self.value = value - - -class ChemicalFormulaExperimentValue(Serializable['ChemicalFormulaExperimentValue'], - ExperimentValue): - """[DEPRECATED] Experiment value for a chemical formula.""" - - value = properties.String('value') - typ = properties.String('type', default='InorganicValue', deserializable=False) - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, value: str): - self.value = value - - -class MolecularStructureExperimentValue(Serializable['MolecularStructureExperimentValue'], - ExperimentValue): - """[DEPRECATED] Experiment value for a molecular structure.""" - - value = properties.String('value') - typ = properties.String('type', default='OrganicValue', deserializable=False) - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, value: str): - self.value = value diff --git a/src/citrine/informatics/predictors/chemical_formula_featurizer.py b/src/citrine/informatics/predictors/chemical_formula_featurizer.py index 40f77d9b1..98f235a37 100644 --- a/src/citrine/informatics/predictors/chemical_formula_featurizer.py +++ b/src/citrine/informatics/predictors/chemical_formula_featurizer.py @@ -1,5 +1,3 @@ -from deprecation import deprecated - from citrine._rest.resource import Resource from citrine._serialization import properties from citrine.informatics.descriptors import ChemicalFormulaDescriptor @@ -152,11 +150,5 @@ def __init__(self, self.excludes = excludes if excludes is not None else [] self.powers = powers if powers is not None else [1.0] - @property - @deprecated(deprecated_in="4.0.0", removed_in="5.0.0", details="Use 'powers' instead.") - def powers_as_float(self) -> list[float]: - """Powers when computing generalized weighted means of element properties.""" - return self.powers - def __str__(self): return ''.format(self.name) diff --git a/src/citrine/resources/branch.py b/src/citrine/resources/branch.py index 83dc00d28..dccd0742e 100644 --- a/src/citrine/resources/branch.py +++ b/src/citrine/resources/branch.py @@ -9,8 +9,6 @@ from citrine.exceptions import NotFound from citrine.resources.data_version_update import BranchDataUpdate, NextBranchVersionRequest from citrine.resources.design_workflow import DesignWorkflowCollection -from citrine.resources.experiment_datasource import (ExperimentDataSourceCollection, - ExperimentDataSource) LATEST_VER = "latest" # Refers to the most recently created branch version. @@ -56,15 +54,6 @@ def design_workflows(self) -> DesignWorkflowCollection: branch_root_id=self.root_id, branch_version=self.version) - @property - def experiment_datasource(self) -> ExperimentDataSource | None: - """Return this branch's experiment data source, or None if one doesn't exist.""" - if getattr(self, 'project_id', None) is None: - raise AttributeError('Cannot retrieve datasource without project reference!') - erds = ExperimentDataSourceCollection(project_id=self.project_id, session=self.session) - branch_erds_iter = erds.list(branch_version_id=self.uid, version=LATEST_VER) - return next(branch_erds_iter, None) - def _post_dump(self, data: dict) -> dict: # Only the data portion of an entity is sent to the server. data = data["data"] diff --git a/src/citrine/resources/experiment_datasource.py b/src/citrine/resources/experiment_datasource.py deleted file mode 100644 index e78ab0fbd..000000000 --- a/src/citrine/resources/experiment_datasource.py +++ /dev/null @@ -1,162 +0,0 @@ -import csv -import json -from collections.abc import Iterator -from functools import partial -from io import StringIO -from uuid import UUID - -from deprecation import deprecated - -from citrine._rest.collection import Collection -from citrine._serialization import properties -from citrine._serialization.serializable import Serializable -from citrine._session import Session -from citrine.informatics.experiment_values import ExperimentValue - - -class CandidateExperimentSnapshot(Serializable['CandidateExperimentSnapshot']): - """The contents of a candidate experiment within an experiment data source.""" - - uid = properties.UUID('experiment_id', serializable=False) - """:UUID: unique Citrine id of this experiment""" - candidate_id = properties.UUID('candidate_id', serializable=False) - """:UUID: unique Citrine id of the candidate associated with this experiment""" - workflow_id = properties.UUID('workflow_id', serializable=False) - """:UUID: unique Citrine id of the design workflow which produced the associated candidate""" - name = properties.String('name', serializable=False) - """:str: name of the experiment""" - description = properties.Optional(properties.String, 'description', serializable=False) - """:str | None: description of the experiment""" - updated_time = properties.Datetime('updated_time', serializable=False) - """:datetime: date and time at which the experiment was updated""" - - overrides = properties.Mapping(properties.String, properties.Object(ExperimentValue), - 'overrides') - """:dict[str, ExperimentValue]: dictionary of candidate material variable overrides""" - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, *args, **kwargs): - """Candidate experiment snapshots are not directly instantiated by the user.""" - pass # pragma: no cover - - def _overrides_json(self) -> dict[str, str]: - return {name: json.dumps(expt_value.value) for name, expt_value in self.overrides.items()} - - -class ExperimentDataSource(Serializable['ExperimentDataSource']): - """An experiment data source.""" - - uid = properties.UUID('id', serializable=False) - """:UUID: unique Citrine id of this experiment data source""" - experiments = properties.List(properties.Object(CandidateExperimentSnapshot), - 'data.experiments', - serializable=False) - """:list[CandidateExperimentSnapshot]: list of experiment data in this data source""" - branch_root_id = properties.UUID('metadata.branch_root_id', serializable=False) - """:UUID: unique Citrine id of the branch root this data source is associated with""" - version = properties.Integer('metadata.version', serializable=False) - """:int: version of this data source""" - created_by = properties.UUID('metadata.created.user', serializable=False) - """:UUID: id of the user who created this data source""" - create_time = properties.Datetime('metadata.created.time', serializable=False) - """:datetime: date and time at which this data source was created""" - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates.") - def __init__(self, *args, **kwargs): - """Experiment data sources are not directly instantiated by the user.""" - pass # pragma: no cover - - def read(self) -> str: - """Read this experiment data source into a CSV. - - Each row will be a single experiment from this data source, and each column is a variable - which is overriden in any of the experiments in this data source. If an experiment did - not override a variable, its cell will be left empty. - - All cells can be deserialized as JSON. Most of them will simply be strings or numbers. But - if present,the "Formulation" cell will contain an escaped JSON string, which will - deserialize into a mapping from ingredient names to floating-point values. - """ - overrides = [experiment._overrides_json() for experiment in self.experiments] - columns = {key for override in overrides for key in override} - sorted_columns = sorted(list(columns), key=str.lower) - - buffer = StringIO() - writer = csv.DictWriter(buffer, sorted_columns) - writer.writeheader() - writer.writerows(overrides) - - return buffer.getvalue() - - -class ExperimentDataSourceCollection(Collection[ExperimentDataSource]): - """[DEPRECATED] The collection of all experiment data sources associated with a project.""" - - _path_template = 'projects/{project_id}/candidate-experiment-datasources' - _individual_key = None - _resource = ExperimentDataSource - _collection_key = 'response' - - @deprecated(deprecated_in="4.1.0", removed_in="5.0.0", - details="Replaced by creating materials from candidates on the platform. " - "Alternatively, you may convert the candidate into a collection of GEMD " - "objects manually.") - def __init__(self, project_id: UUID, session: Session): - self.project_id = project_id - self.session: Session = session - - def build(self, data: dict) -> ExperimentDataSource: - """Build an individual experiment result from a dictionary.""" - result = ExperimentDataSource.build(data) - result._project_id = self.project_id - result._session = self.session - return result - - def list(self, *, - per_page: int = 100, - branch_version_id: UUID | str | None = None, - version: int | str | None = None) -> Iterator[ExperimentDataSource]: - """Paginate over the experiment data sources. - - Parameters - --------- - per_page: int, optional - Max number of results to return per page. Default is 100. This parameter - is used when making requests to the backend service. If the page parameter - is specified it limits the maximum number of elements in the response. - branch_version_id: UUID, optional - Filter the list by the branch version ID. - version: int | str, optional - Filter the list by the data source version. Also accepts "latest". - - Returns - ------- - Iterator[ExperimentDataSource] - An iterator that can be used to loop over all matching experiment data sources. - - """ - params = {} - if branch_version_id: - params["branch"] = str(branch_version_id) - if version: - params["version"] = version - - fetcher = partial(self._fetch_page, additional_params=params) - return self._paginator.paginate(page_fetcher=fetcher, - collection_builder=self._build_collection_elements, - per_page=per_page) - - def read(self, datasource: ExperimentDataSource | UUID | str): - """Reads the provided experiment data source into a CSV. - - If a UUID or str is provided, it's first retrieved from the platform. - - For details on the CSV format, see - :py:meth:`citrine.resources.experiment_datasource.ExperimentDataSource.read`. - """ - if not isinstance(datasource, ExperimentDataSource): - datasource = self.get(uid=datasource) - - return datasource.read() diff --git a/src/citrine/resources/predictor.py b/src/citrine/resources/predictor.py index fad6dd839..fb7f58766 100644 --- a/src/citrine/resources/predictor.py +++ b/src/citrine/resources/predictor.py @@ -1,5 +1,4 @@ """Resources that represent collections of predictors.""" -import warnings from collections.abc import Iterable from functools import partial from typing import Any @@ -12,7 +11,7 @@ from citrine._rest.paginator import Paginator from citrine._serialization import properties from citrine._session import Session -from citrine.informatics.data_sources import DataSource, ExperimentDataSourceRef +from citrine.informatics.data_sources import DataSource from citrine.informatics.design_candidate import HierarchicalDesignMaterial from citrine.informatics.predictors import GraphPredictor from citrine.resources.status_detail import StatusDetail @@ -108,16 +107,6 @@ def _page_fetcher(self, *, uid: UUID | str, **additional_params): } return partial(self._fetch_page, **fetcher_params) - def _check_data_sources(self, predictor: GraphPredictor): - for data_source in predictor.training_data: - print(data_source) - if isinstance(data_source, ExperimentDataSourceRef): - warnings.warn("This predictor contains an experiment result, which is being " - "replaced by creating materials from candidates on the platform. " - "Alternatively, you may convert the candidate into a collection of " - "GEMD objects manually.", - DeprecationWarning) - def build(self, data: dict) -> GraphPredictor: """Build an individual Predictor.""" predictor: GraphPredictor = GraphPredictor.build(data) @@ -132,7 +121,6 @@ def get(self, path = self._construct_path(uid, version) entity = self.session.get_resource(path, version=self._api_version) predictor = self.build(entity) - self._check_data_sources(predictor) return predictor def get_featurized_training_data( diff --git a/tests/conftest.py b/tests/conftest.py index aa9b40448..09468f5fc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -286,24 +286,6 @@ def valid_graph_predictor_data_empty(): return PredictorEntityDataFactory(data=PredictorDataDataFactory(instance=instance)) -@pytest.fixture -def valid_deprecated_expression_predictor_data(): - """Produce valid data used for tests.""" - from citrine.informatics.descriptors import RealDescriptor - shear_modulus = RealDescriptor('Property~Shear modulus', lower_bound=0, upper_bound=100, units='GPa') - return dict( - type='Expression', - name='Expression predictor', - description='Computes shear modulus from Youngs modulus and Poissons ratio', - expression='Y / (2 * (1 + v))', - output=shear_modulus.dump(), - aliases={ - 'Y': "Property~Young's modulus", - 'v': "Property~Poisson's ratio", - } - ) - - @pytest.fixture def valid_expression_predictor_data(): """Produce valid data used for tests.""" @@ -813,8 +795,6 @@ def generic_entity(): "status": "INPROGRESS", "status_description": "VALIDATING", "status_detail": [{"level": "Info", "msg": "System processing"}], - "experimental": False, - "experimental_reasons": [], "create_time": '2020-04-23T15:46:26Z', "update_time": '2020-04-23T15:46:26Z', "created_by": user, diff --git a/tests/informatics/test_data_source.py b/tests/informatics/test_data_source.py index 9bc8f04a2..823506698 100644 --- a/tests/informatics/test_data_source.py +++ b/tests/informatics/test_data_source.py @@ -3,9 +3,7 @@ import pytest -from citrine.informatics.data_sources import ( - DataSource, ExperimentDataSourceRef, GemTableDataSource, SnapshotDataSource -) +from citrine.informatics.data_sources import DataSource, GemTableDataSource, SnapshotDataSource from citrine.informatics.descriptors import RealDescriptor from citrine.resources.file_link import FileLink from citrine.resources.gemtables import GemTable @@ -20,12 +18,6 @@ def data_source(request): return request.param -@pytest.fixture -def deprecated_data_source(): - with pytest.deprecated_call(): - return ExperimentDataSourceRef(datasource_id=uuid.uuid4()) - - def test_deser_from_parent(data_source): # Serialize and deserialize the descriptors, making sure they are round-trip serializable data = data_source.dump() @@ -33,13 +25,6 @@ def test_deser_from_parent(data_source): assert data_source == data_source_deserialized -def test_deser_from_parent_deprecated(deprecated_data_source): - # Serialize and deserialize the descriptors, making sure they are round-trip serializable - data = deprecated_data_source.dump() - data_source_deserialized = DataSource.build(data) - assert deprecated_data_source == data_source_deserialized - - def test_invalid_eq(data_source): other = None assert not data_source == other @@ -53,10 +38,6 @@ def test_invalid_deser(): DataSource.build({"type": "foo"}) -def test_deprecated_data_source_id(deprecated_data_source): - with pytest.deprecated_call(): - assert deprecated_data_source == DataSource.from_data_source_id(deprecated_data_source.to_data_source_id()) - def test_data_source_id(data_source): assert data_source == DataSource.from_data_source_id(data_source.to_data_source_id()) diff --git a/tests/informatics/test_experiment_values.py b/tests/informatics/test_experiment_values.py deleted file mode 100644 index 0c6427803..000000000 --- a/tests/informatics/test_experiment_values.py +++ /dev/null @@ -1,46 +0,0 @@ -import uuid - -import pytest - -from citrine.informatics.experiment_values import ExperimentValue, \ - RealExperimentValue, \ - IntegerExperimentValue, \ - CategoricalExperimentValue, \ - MixtureExperimentValue, \ - ChemicalFormulaExperimentValue, \ - MolecularStructureExperimentValue - - -@pytest.fixture(params=[ - (CategoricalExperimentValue, ("categorical", )), - (ChemicalFormulaExperimentValue, ("(Ca)1(O)3(Si)1",)), - (IntegerExperimentValue, (7,)), - (MixtureExperimentValue, ({"ingredient1": 0.3, "ingredient2": 0.7},)), - (MolecularStructureExperimentValue, ("CC1(CC(CC(N1)(C)C)NCCCCCCNC2CC(NC(C2)(C)C)(C)C)C.C1COCCN1C2=NC(=NC(=N2)Cl)Cl",)), - (RealExperimentValue, (3.5,)) -]) -def experiment_value(request): - cls, args = request.param - with pytest.deprecated_call(): - return cls(*args) - - -def test_deser_from_parent(experiment_value): - # Serialize and deserialize the experiment values, making sure they are round-trip serializable - data = experiment_value.dump() - with pytest.deprecated_call(): - experiment_value_deserialized = ExperimentValue.build(data) - assert experiment_value == experiment_value_deserialized - - -def test_invalid_eq(experiment_value): - other = None - assert not experiment_value == other - - -def test_string_rep(experiment_value): - """String representation of experiment value should contain the type and value.""" - assert str(experiment_value.value) in str(experiment_value) - assert experiment_value.__class__.__name__ in str(experiment_value) - assert str(experiment_value.value) in repr(experiment_value) - assert experiment_value.__class__.__name__ in repr(experiment_value) diff --git a/tests/informatics/test_predictors.py b/tests/informatics/test_predictors.py index e1f7c1c57..6761cafe4 100644 --- a/tests/informatics/test_predictors.py +++ b/tests/informatics/test_predictors.py @@ -275,8 +275,6 @@ def test_chemical_featurizer(chemical_featurizer): assert chemical_featurizer.features == ["standard"] assert chemical_featurizer.excludes == [] assert chemical_featurizer.powers == [1.0, 2.0] - with pytest.warns(DeprecationWarning): - assert chemical_featurizer.powers_as_float == [1.0, 2.0] assert str(chemical_featurizer) == "" @@ -291,8 +289,6 @@ def test_chemical_featurizer(chemical_featurizer): } chemical_featurizer.powers = [0.5, -1.0] - with pytest.warns(DeprecationWarning): - assert chemical_featurizer.powers_as_float == [0.5, -1.0] assert chemical_featurizer.powers == [0.5, -1.0] diff --git a/tests/resources/test_branch.py b/tests/resources/test_branch.py index bd1581861..c063c748a 100644 --- a/tests/resources/test_branch.py +++ b/tests/resources/test_branch.py @@ -9,7 +9,6 @@ from citrine.resources.data_version_update import NextBranchVersionRequest, DataVersionUpdate, BranchDataUpdate from citrine.resources.branch import Branch, BranchCollection from tests.utils.factories import BranchDataFactory, BranchRootDataFactory, \ - CandidateExperimentSnapshotDataFactory, ExperimentDataSourceDataFactory, \ BranchDataFieldFactory, BranchMetadataFieldFactory, BranchDataUpdateFactory from tests.utils.session import FakeSession, FakeCall, FakePaginatedSession @@ -525,44 +524,3 @@ def test_branch_data_updates_nochange(session, collection, branch_path): v2branch = collection.update_data(root_id=branch.root_id, version=branch.version) assert v2branch is None - - -def test_experiment_datasource(session, collection): - # Given - erds_path = f'projects/{collection.project_id}/candidate-experiment-datasources' - - erds = ExperimentDataSourceDataFactory() - - branch = collection.build(BranchDataFactory()) - session.set_response({'response': [erds]}) - - # When / Then - with pytest.deprecated_call(): - assert branch.experiment_datasource is not None - - assert session.calls == [ - FakeCall(method='GET', path=erds_path, params={'branch': str(branch.uid), 'version': LATEST_VER, 'per_page': 100, 'page': 1}) - ] - - -def test_no_experiment_datasource(session, collection): - # Given - erds_path = f'projects/{collection.project_id}/candidate-experiment-datasources' - branch = collection.build(BranchDataFactory()) - session.set_response({'response': []}) - - # When / Then - with pytest.deprecated_call(): - assert branch.experiment_datasource is None - - assert session.calls == [ - FakeCall(method='GET', path=erds_path, params={'branch': str(branch.uid), 'version': LATEST_VER, 'per_page': 100, 'page': 1}) - ] - - -def test_experiment_data_source_no_project_id(session): - branch = BranchCollection(None, session).build(BranchDataFactory()) - with pytest.raises(AttributeError): - branch.experiment_datasource - - assert not session.calls diff --git a/tests/resources/test_experiment_datasource.py b/tests/resources/test_experiment_datasource.py deleted file mode 100644 index 4e4e1bf4d..000000000 --- a/tests/resources/test_experiment_datasource.py +++ /dev/null @@ -1,111 +0,0 @@ -import csv -import io -import json -import uuid - -import pytest - -from citrine.resources.experiment_datasource import ExperimentDataSource, ExperimentDataSourceCollection -from tests.utils.factories import ExperimentDataSourceDataFactory -from tests.utils.session import ( - FakeCall, - FakeSession -) - - -LATEST_VER = "latest" - - -@pytest.fixture -def session(): - return FakeSession() - - -@pytest.fixture -def collection(session) -> ExperimentDataSourceCollection: - with pytest.deprecated_call(): - return ExperimentDataSourceCollection(uuid.uuid4(), session) - - -@pytest.fixture -def erds_base_path(collection): - return f'projects/{collection.project_id}/candidate-experiment-datasources' - - -def assert_erds_csv(erds_csv, erds_dict): - for row, expt in zip(csv.DictReader(io.StringIO(erds_csv)), erds_dict["data"]["experiments"]): - for variable, actual_value_raw in row.items(): - assert expt["overrides"][variable]["value"] == json.loads(actual_value_raw) - - -def test_build(collection): - erds_dict = ExperimentDataSourceDataFactory() - actual_erds: ExperimentDataSource = collection.build(erds_dict) - - assert str(actual_erds.uid) == erds_dict["id"] - assert str(actual_erds.branch_root_id) == erds_dict["metadata"]["branch_root_id"] - assert actual_erds.version == erds_dict["metadata"]["version"] - assert str(actual_erds.created_by) == erds_dict["metadata"]["created"]["user"] - # TODO: It'd be better to actually invoke the Datetime._serialize method - assert int(actual_erds.create_time.timestamp() * 1000 + 0.0001) == erds_dict["metadata"]["created"]["time"] - - for actual_experiment, erds_experiment in zip(actual_erds.experiments, erds_dict["data"]["experiments"]): - assert str(actual_experiment.uid) == erds_experiment["experiment_id"] - assert str(actual_experiment.candidate_id) == erds_experiment["candidate_id"] - assert str(actual_experiment.workflow_id) == erds_experiment["workflow_id"] - assert actual_experiment.name == erds_experiment["name"] - assert actual_experiment.description == erds_experiment["description"] - # TODO: It'd be better to actually invoke the Datetime._serialize method - assert int(actual_experiment.updated_time.timestamp() * 1000 + 0.0001) == erds_experiment["updated_time"] - - for actual_override, erds_override in zip(actual_experiment.overrides.items(), erds_experiment["overrides"].items()): - actual_override_key, actual_override_value = actual_override - erds_override_key, erds_override_value = erds_override - assert actual_override_key == erds_override_key - assert actual_override_value.typ == erds_override_value["type"] - assert actual_override_value.value == erds_override_value["value"] - - -def test_list(session, collection, erds_base_path): - version_id = uuid.uuid4() - - session.set_response({"response": []}) - - list(collection.list()) - list(collection.list(branch_version_id=version_id)) - list(collection.list(version=4)) - list(collection.list(version=LATEST_VER)) - list(collection.list(branch_version_id=version_id, version=12)) - list(collection.list(branch_version_id=version_id, version=LATEST_VER)) - - assert session.calls == [ - FakeCall(method='GET', path=erds_base_path, params={'per_page': 100, 'page': 1}), - FakeCall(method='GET', path=erds_base_path, params={'per_page': 100, "branch": str(version_id), 'page': 1}), - FakeCall(method='GET', path=erds_base_path, params={'per_page': 100, "version": 4, 'page': 1}), - FakeCall(method='GET', path=erds_base_path, params={'per_page': 100, "version": LATEST_VER, 'page': 1}), - FakeCall(method='GET', path=erds_base_path, params={'per_page': 100, "branch": str(version_id), "version": 12, 'page': 1}), - FakeCall(method='GET', path=erds_base_path, params={'per_page': 100, "branch": str(version_id), "version": LATEST_VER, 'page': 1}) - ] - - -def test_read_and_retrieve(session, collection, erds_base_path): - erds_dict = ExperimentDataSourceDataFactory() - erds_id = uuid.uuid4() - erds_path = f"{erds_base_path}/{erds_id}" - - session.set_response(erds_dict) - - erds_csv = collection.read(erds_id) - - assert session.calls == [FakeCall(method='GET', path=erds_path)] - assert_erds_csv(erds_csv, erds_dict) - - -def test_read_from_obj(session, collection): - erds_dict = ExperimentDataSourceDataFactory() - erds_obj = collection.build(erds_dict) - - erds_csv = collection.read(erds_obj) - - assert not session.calls - assert_erds_csv(erds_csv, erds_dict) diff --git a/tests/resources/test_predictor.py b/tests/resources/test_predictor.py index 9eaf206ec..efce269ec 100644 --- a/tests/resources/test_predictor.py +++ b/tests/resources/test_predictor.py @@ -5,7 +5,7 @@ from copy import deepcopy from citrine.exceptions import BadRequest, Conflict, ModuleRegistrationFailedException, NotFound -from citrine.informatics.data_sources import ExperimentDataSourceRef, GemTableDataSource +from citrine.informatics.data_sources import GemTableDataSource from citrine.informatics.descriptors import RealDescriptor from citrine.informatics.predictors import ( AutoMLPredictor, @@ -754,20 +754,3 @@ def test_rename_description_only(valid_graph_predictor_data): versions_path = _PredictorVersionCollection._path_template.format(project_id=pc.project_id, uid=pred_id) expected_payload = {"name": None, "description": new_description} assert session.calls == [FakeCall(method="PUT", path=f"{versions_path}/{pred_version}/rename", json=expected_payload)] - - -def test_get_predictor_with_experiment_data_source_deprecated(valid_graph_predictor_data): - # Given - session = FakeSession() - pc = PredictorCollection(uuid.uuid4(), session) - - with pytest.deprecated_call(): - erds = ExperimentDataSourceRef(datasource_id=uuid.uuid4()) - entity = deepcopy(valid_graph_predictor_data) - entity["data"]["instance"]["training_data"] = [erds.dump()] - - session.set_responses(entity) - - # When - with pytest.deprecated_call(): - pc.get(uuid.uuid4()) diff --git a/tests/utils/factories.py b/tests/utils/factories.py index 5156e6de7..f897b9910 100644 --- a/tests/utils/factories.py +++ b/tests/utils/factories.py @@ -815,70 +815,6 @@ class Meta: constraints = [] # TODO make a ConstraintDataFactory -class CategoricalExperimentValueDataFactory(factory.DictFactory): - type = "CategoricalValue" - value = factory.Faker('company') - - -class ChemicalFormulaExperimentValueDataFactory(factory.DictFactory): - type = "InorganicValue" - value = factory.Faker('random_formula') - - -class IntegerExperimentValueDataFactory(factory.DictFactory): - type = "IntegerValue" - value = factory.Faker('random_int', min=1, max=99) - - -class MixtureExperimentValueDataFactory(factory.DictFactory): - type = "MixtureValue" - value = factory.Dict({"ingredient1": 0.3, "ingredient2": 0.7}) - - -class MolecularStructureExperimentValueDataFactory(factory.DictFactory): - type = "OrganicValue" - value = factory.Faker('random_smiles') - - -class RealExperimentValueDataFactory(factory.DictFactory): - type = "RealValue" - value = factory.Faker('pyfloat', min_value=0, max_value=100) - - -class CandidateExperimentSnapshotDataFactory(factory.DictFactory): - experiment_id = factory.Faker('uuid4') - candidate_id = factory.Faker('uuid4') - workflow_id = factory.Faker('uuid4') - name = factory.Faker('company') - description = factory.Faker('company') - updated_time = factory.Faker("unix_milliseconds") - # TODO Generate Experiment keys randomly but uniquely - overrides = factory.Dict({ - "ingredient1": factory.SubFactory(CategoricalExperimentValueDataFactory), - "ingredient2": factory.SubFactory(ChemicalFormulaExperimentValueDataFactory), - "ingredient3": factory.SubFactory(IntegerExperimentValueDataFactory), - "Formulation": factory.SubFactory(MixtureExperimentValueDataFactory), - "ingredient4": factory.SubFactory(MolecularStructureExperimentValueDataFactory), - "ingredient5": factory.SubFactory(RealExperimentValueDataFactory) - }) - - -class ExperimentDataSourceDataDataFactory(factory.DictFactory): - experiments = factory.List([factory.SubFactory(CandidateExperimentSnapshotDataFactory)]) - - -class ExperimentDataSourceMetadataDataFactory(factory.DictFactory): - branch_root_id = factory.Faker('uuid4') - version = factory.Faker('random_digit_not_null') - created = factory.SubFactory(UserTimestampDataFactory) - - -class ExperimentDataSourceDataFactory(factory.DictFactory): - id = factory.Faker('uuid4') - data = factory.SubFactory(ExperimentDataSourceDataDataFactory) - metadata = factory.SubFactory(ExperimentDataSourceMetadataDataFactory) - - class AnalysisPlotMetadataDataFactory(factory.DictFactory): rank = factory.Faker('random_int', min=1, max=10) created = factory.SubFactory(UserTimestampDataFactory) diff --git a/tests/utils/fakes/fake_workflow_collection.py b/tests/utils/fakes/fake_workflow_collection.py index 6c1ba2587..6de507cf5 100644 --- a/tests/utils/fakes/fake_workflow_collection.py +++ b/tests/utils/fakes/fake_workflow_collection.py @@ -2,7 +2,6 @@ from uuid import uuid4, UUID from citrine._session import Session -from citrine._utils.functions import migrate_deprecated_argument from citrine.informatics.workflows import DesignWorkflow from citrine.resources.design_workflow import DesignWorkflowCollection