From 16427badc3bf2aa54bfbeb91ccc02ba683e19a29 Mon Sep 17 00:00:00 2001 From: Wes John-Alder Date: Thu, 12 Nov 2026 09:14:58 -0500 Subject: [PATCH 1/2] PNE-9649: Deprecate ProcessTemplate allowed_names Setting a non-empty allowed_names now emits a DeprecationWarning. The Citrine Platform ignores the field, and it will be removed in 4.0.0. The constructor argument, property, and JSON round-trip still work. The cake demo no longer sets the field. Bump the version to 3.1.0. Co-Authored-By: Claude Opus 5.5 --- gemd/__version__.py | 2 +- gemd/demo/cake.py | 2 - gemd/entity/template/process_template.py | 23 +++++++--- .../entity/template/test_process_template.py | 43 ++++++++++++++++--- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/gemd/__version__.py b/gemd/__version__.py index 131942e..f5f41e5 100644 --- a/gemd/__version__.py +++ b/gemd/__version__.py @@ -1 +1 @@ -__version__ = "3.0.2" +__version__ = "3.1.0" diff --git a/gemd/demo/cake.py b/gemd/demo/cake.py index fe4b0cb..80b57a1 100644 --- a/gemd/demo/cake.py +++ b/gemd/demo/cake.py @@ -195,12 +195,10 @@ def make_cake_templates(): tmpl["Procuring"] = ProcessTemplate( name="Procuring", description="Buyin' stuff", - allowed_names=[], # Takes no ingredients by definition ) tmpl["Baking"] = ProcessTemplate( name="Baking", description="Using heat to promote chemical reactions in a material", - allowed_names=["batter"], allowed_labels=["precursor"], conditions=[(tmpl["Oven temperature"], RealBounds(0, 700, "degF"))], parameters=[(tmpl["Oven temperature setting"], RealBounds(100, 550, "degF"))], diff --git a/gemd/entity/template/process_template.py b/gemd/entity/template/process_template.py index 443f406..2ae37c7 100644 --- a/gemd/entity/template/process_template.py +++ b/gemd/entity/template/process_template.py @@ -1,5 +1,7 @@ """A process template.""" +from warnings import warn + from gemd.entity.setters import validate_list from gemd.entity.template.base_template import BaseTemplate from gemd.entity.template.has_condition_templates import HasConditionTemplates @@ -32,11 +34,10 @@ class ProcessTemplate( are hierarchical strings that store information about an entity. They can be used for filtering and discoverability. allowed_names: List[str], optional - Deprecated. This field does not limit ingredient names. - The Citrine Platform ignores this list when you save a template. When you fetch a - template, this list has the distinct ingredient names from process specs that use - the template. Names come from datasets you can read. GEMD Python keeps this field - to give users time to migrate code and JSON away from it. + Deprecated as of 3.1.0, and will be removed in 4.0.0. + This field does not limit ingredient names. The Citrine Platform ignores this list. + It discovers ingredient names from the ingredient specs that use the process. + Setting a non-empty list emits a DeprecationWarning. allowed_labels: List[str], optional The set of labels that a process' ingredients are allowed to use in their labels field. conditions: List[~gemd.entity.template.condition_template.ConditionTemplate] or \ @@ -78,7 +79,10 @@ def __init__( @property def allowed_names(self): - """Get the allowed names.""" + """Get the allowed names. + + Deprecated as of 3.1.0, and will be removed in 4.0.0. + """ return self._allowed_names @allowed_names.setter @@ -87,6 +91,13 @@ def allowed_names(self, allowed_names): self._allowed_names = validate_list([], str) else: self._allowed_names = validate_list(allowed_names, str) + if len(self._allowed_names) > 0: + warn( + "allowed_names is deprecated as of 3.1.0 and will be removed in 4.0.0. " + "The Citrine Platform ignores it.", + DeprecationWarning, + stacklevel=2, + ) @property def allowed_labels(self): diff --git a/tests/entity/template/test_process_template.py b/tests/entity/template/test_process_template.py index e3f8d39..21f222d 100644 --- a/tests/entity/template/test_process_template.py +++ b/tests/entity/template/test_process_template.py @@ -1,5 +1,7 @@ """Tests of the ProcessTemplate object.""" +import warnings + import pytest from gemd.entity.bounds import IntegerBounds @@ -20,16 +22,45 @@ def test_bounds_mismatch(): def test_allowed_names(): - """Test that allowed_names can be assigned. - - Presently allowed_names is not used for any validation, but this test can be expanded - if it is used in the future. - """ + """Test that allowed_names can be assigned, and that doing so warns of its deprecation.""" allowed_names = ["THF", "Carbon Disulfide", "Dimethyl Ether"] - proc_template = ProcessTemplate(name="test template", allowed_names=allowed_names) + with pytest.warns(DeprecationWarning, match="allowed_names"): + proc_template = ProcessTemplate(name="test template", allowed_names=allowed_names) for name in allowed_names: assert name in proc_template.allowed_names + with pytest.warns(DeprecationWarning, match="allowed_names"): + proc_template.allowed_names = ["Water"] + assert proc_template.allowed_names == ["Water"] + + +@pytest.mark.parametrize("allowed_names", [None, []]) +def test_allowed_names_empty_does_not_warn(allowed_names): + """Test that omitting allowed_names, or passing an empty list, emits no warning.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + proc_template = ProcessTemplate(name="test template", allowed_names=allowed_names) + assert proc_template.allowed_names == [] + assert ProcessTemplate(name="no names").allowed_names == [] + + +def test_allowed_names_json_round_trip(): + """Test that JSON with and without allowed_names still loads and round-trips.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + without_names = ProcessTemplate.build({"type": "process_template", "name": "bare"}) + assert without_names.allowed_names == [] + assert loads(dumps(without_names)).allowed_names == [] + + with pytest.warns(DeprecationWarning, match="allowed_names"): + with_names = ProcessTemplate.build( + {"type": "process_template", "name": "named", "allowed_names": ["batter"]} + ) + assert with_names.allowed_names == ["batter"] + with pytest.warns(DeprecationWarning, match="allowed_names"): + copied = loads(dumps(with_names)) + assert copied.allowed_names == ["batter"] + def test_allowed_labels(): """Test that allowed_labels can be assigned. From 042da75af66fb40d062864c2c086a66dbe1b5f62 Mon Sep 17 00:00:00 2001 From: Wes John-Alder Date: Thu, 12 Nov 2026 09:18:38 -0500 Subject: [PATCH 2/2] PNE-9649: Remove allowed_names from ProcessTemplate The Citrine Platform no longer uses process-template allowed_names. Remove the constructor argument, the property, and the deprecation warning, along with their tests. JSON that still has the field loads, and the loader logs that it ignores the unexpected key. Bump the version to 4.0.0 for the breaking change. Co-Authored-By: Claude Opus 5.5 --- gemd/__version__.py | 2 +- gemd/entity/template/process_template.py | 33 -------------- .../entity/template/test_process_template.py | 43 ------------------- 3 files changed, 1 insertion(+), 77 deletions(-) diff --git a/gemd/__version__.py b/gemd/__version__.py index f5f41e5..ce1305b 100644 --- a/gemd/__version__.py +++ b/gemd/__version__.py @@ -1 +1 @@ -__version__ = "3.1.0" +__version__ = "4.0.0" diff --git a/gemd/entity/template/process_template.py b/gemd/entity/template/process_template.py index 2ae37c7..ce01489 100644 --- a/gemd/entity/template/process_template.py +++ b/gemd/entity/template/process_template.py @@ -1,7 +1,5 @@ """A process template.""" -from warnings import warn - from gemd.entity.setters import validate_list from gemd.entity.template.base_template import BaseTemplate from gemd.entity.template.has_condition_templates import HasConditionTemplates @@ -33,11 +31,6 @@ class ProcessTemplate( `Tags `_ are hierarchical strings that store information about an entity. They can be used for filtering and discoverability. - allowed_names: List[str], optional - Deprecated as of 3.1.0, and will be removed in 4.0.0. - This field does not limit ingredient names. The Citrine Platform ignores this list. - It discovers ingredient names from the ingredient specs that use the process. - Setting a non-empty list emits a DeprecationWarning. allowed_labels: List[str], optional The set of labels that a process' ingredients are allowed to use in their labels field. conditions: List[~gemd.entity.template.condition_template.ConditionTemplate] or \ @@ -62,7 +55,6 @@ def __init__( description=None, conditions=None, parameters=None, - allowed_names=None, allowed_labels=None, uids=None, tags=None, @@ -71,34 +63,9 @@ def __init__( HasConditionTemplates.__init__(self, conditions) HasParameterTemplates.__init__(self, parameters) - self._allowed_names = None - self.allowed_names = allowed_names - self._allowed_labels = None self.allowed_labels = allowed_labels - @property - def allowed_names(self): - """Get the allowed names. - - Deprecated as of 3.1.0, and will be removed in 4.0.0. - """ - return self._allowed_names - - @allowed_names.setter - def allowed_names(self, allowed_names): - if allowed_names is None: - self._allowed_names = validate_list([], str) - else: - self._allowed_names = validate_list(allowed_names, str) - if len(self._allowed_names) > 0: - warn( - "allowed_names is deprecated as of 3.1.0 and will be removed in 4.0.0. " - "The Citrine Platform ignores it.", - DeprecationWarning, - stacklevel=2, - ) - @property def allowed_labels(self): """Get the allowed labels.""" diff --git a/tests/entity/template/test_process_template.py b/tests/entity/template/test_process_template.py index 21f222d..f6891b8 100644 --- a/tests/entity/template/test_process_template.py +++ b/tests/entity/template/test_process_template.py @@ -1,7 +1,5 @@ """Tests of the ProcessTemplate object.""" -import warnings - import pytest from gemd.entity.bounds import IntegerBounds @@ -21,47 +19,6 @@ def test_bounds_mismatch(): ProcessTemplate("a process template", conditions=[[cond_template, object_bounds]]) -def test_allowed_names(): - """Test that allowed_names can be assigned, and that doing so warns of its deprecation.""" - allowed_names = ["THF", "Carbon Disulfide", "Dimethyl Ether"] - with pytest.warns(DeprecationWarning, match="allowed_names"): - proc_template = ProcessTemplate(name="test template", allowed_names=allowed_names) - for name in allowed_names: - assert name in proc_template.allowed_names - - with pytest.warns(DeprecationWarning, match="allowed_names"): - proc_template.allowed_names = ["Water"] - assert proc_template.allowed_names == ["Water"] - - -@pytest.mark.parametrize("allowed_names", [None, []]) -def test_allowed_names_empty_does_not_warn(allowed_names): - """Test that omitting allowed_names, or passing an empty list, emits no warning.""" - with warnings.catch_warnings(): - warnings.simplefilter("error", DeprecationWarning) - proc_template = ProcessTemplate(name="test template", allowed_names=allowed_names) - assert proc_template.allowed_names == [] - assert ProcessTemplate(name="no names").allowed_names == [] - - -def test_allowed_names_json_round_trip(): - """Test that JSON with and without allowed_names still loads and round-trips.""" - with warnings.catch_warnings(): - warnings.simplefilter("error", DeprecationWarning) - without_names = ProcessTemplate.build({"type": "process_template", "name": "bare"}) - assert without_names.allowed_names == [] - assert loads(dumps(without_names)).allowed_names == [] - - with pytest.warns(DeprecationWarning, match="allowed_names"): - with_names = ProcessTemplate.build( - {"type": "process_template", "name": "named", "allowed_names": ["batter"]} - ) - assert with_names.allowed_names == ["batter"] - with pytest.warns(DeprecationWarning, match="allowed_names"): - copied = loads(dumps(with_names)) - assert copied.allowed_names == ["batter"] - - def test_allowed_labels(): """Test that allowed_labels can be assigned.