gemd 2.3.2__tar.gz → 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. {gemd-2.3.2 → gemd-3.0.0}/PKG-INFO +2 -4
  2. gemd-3.0.0/gemd/__version__.py +1 -0
  3. {gemd-2.3.2 → gemd-3.0.0}/gemd/builders/impl.py +13 -14
  4. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/strehlow_and_cook.py +1 -1
  5. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/attribute/base_attribute.py +10 -10
  6. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/attribute/condition.py +1 -3
  7. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/attribute/parameter.py +1 -3
  8. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/attribute/property.py +1 -3
  9. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/attribute/property_and_conditions.py +4 -4
  10. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/base_entity.py +8 -9
  11. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds/base_bounds.py +4 -4
  12. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds/categorical_bounds.py +9 -8
  13. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds/composition_bounds.py +6 -5
  14. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds/integer_bounds.py +4 -4
  15. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds/molecular_structure_bounds.py +4 -6
  16. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds/real_bounds.py +4 -4
  17. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/case_insensitive_dict.py +33 -11
  18. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/dict_serializable.py +11 -12
  19. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/has_dependencies.py +2 -2
  20. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/base_object.py +4 -4
  21. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_conditions.py +5 -5
  22. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_material.py +3 -4
  23. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_parameters.py +5 -5
  24. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_process.py +3 -4
  25. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_properties.py +5 -5
  26. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_quantities.py +1 -1
  27. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_source.py +1 -1
  28. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_spec.py +6 -7
  29. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_template.py +5 -6
  30. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/has_template_check_generator.py +3 -2
  31. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/ingredient_run.py +14 -13
  32. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/ingredient_spec.py +10 -10
  33. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/material_run.py +11 -10
  34. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/material_spec.py +11 -13
  35. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/measurement_run.py +10 -10
  36. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/measurement_spec.py +6 -6
  37. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/process_run.py +10 -9
  38. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/process_spec.py +10 -9
  39. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/setters.py +5 -4
  40. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/base_template.py +5 -5
  41. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/has_condition_templates.py +8 -7
  42. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/has_parameter_templates.py +8 -7
  43. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/has_property_templates.py +9 -8
  44. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/util.py +2 -2
  45. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/valid_list.py +4 -3
  46. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/discrete_categorical.py +3 -3
  47. {gemd-2.3.2 → gemd-3.0.0}/gemd/enumeration/base_enumeration.py +4 -5
  48. {gemd-2.3.2 → gemd-3.0.0}/gemd/json/gemd_json.py +5 -5
  49. {gemd-2.3.2 → gemd-3.0.0}/gemd/units/__init__.py +2 -0
  50. {gemd-2.3.2 → gemd-3.0.0}/gemd/units/impl.py +28 -47
  51. {gemd-2.3.2 → gemd-3.0.0}/gemd/util/impl.py +19 -29
  52. {gemd-2.3.2 → gemd-3.0.0}/gemd.egg-info/PKG-INFO +2 -4
  53. gemd-3.0.0/gemd.egg-info/requires.txt +2 -0
  54. {gemd-2.3.2 → gemd-3.0.0}/pyproject.toml +8 -15
  55. gemd-2.3.2/gemd/__version__.py +0 -1
  56. gemd-2.3.2/gemd.egg-info/requires.txt +0 -5
  57. {gemd-2.3.2 → gemd-3.0.0}/LICENSE +0 -0
  58. {gemd-2.3.2 → gemd-3.0.0}/README.md +0 -0
  59. {gemd-2.3.2 → gemd-3.0.0}/gemd/__init__.py +0 -0
  60. {gemd-2.3.2 → gemd-3.0.0}/gemd/builders/__init__.py +0 -0
  61. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/__init__.py +0 -0
  62. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/cake.py +0 -0
  63. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/material_run_example.py +0 -0
  64. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/measurement_example.py +0 -0
  65. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/strehlow_and_cook.pif +0 -0
  66. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/strehlow_and_cook_small.pif +0 -0
  67. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/table_example.py +0 -0
  68. {gemd-2.3.2 → gemd-3.0.0}/gemd/demo/toothpick.jpg +0 -0
  69. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/__init__.py +0 -0
  70. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/attribute/__init__.py +0 -0
  71. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds/__init__.py +0 -0
  72. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/bounds_validation.py +0 -0
  73. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/file_link.py +0 -0
  74. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/link_by_uid.py +0 -0
  75. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/object/__init__.py +0 -0
  76. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/source/__init__.py +0 -0
  77. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/source/performed_source.py +0 -0
  78. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/__init__.py +0 -0
  79. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/attribute_template.py +0 -0
  80. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/condition_template.py +0 -0
  81. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/material_template.py +0 -0
  82. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/measurement_template.py +0 -0
  83. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/parameter_template.py +0 -0
  84. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/process_template.py +0 -0
  85. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/template/property_template.py +0 -0
  86. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/__init__.py +0 -0
  87. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/base_value.py +0 -0
  88. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/categorical_value.py +0 -0
  89. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/composition_value.py +0 -0
  90. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/continuous_value.py +0 -0
  91. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/empirical_formula.py +0 -0
  92. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/inchi_value.py +0 -0
  93. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/integer_value.py +0 -0
  94. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/molecular_value.py +0 -0
  95. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/nominal_categorical.py +0 -0
  96. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/nominal_composition.py +0 -0
  97. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/nominal_integer.py +0 -0
  98. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/nominal_real.py +0 -0
  99. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/normal_real.py +0 -0
  100. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/smiles_value.py +0 -0
  101. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/uniform_integer.py +0 -0
  102. {gemd-2.3.2 → gemd-3.0.0}/gemd/entity/value/uniform_real.py +0 -0
  103. {gemd-2.3.2 → gemd-3.0.0}/gemd/enumeration/__init__.py +0 -0
  104. {gemd-2.3.2 → gemd-3.0.0}/gemd/enumeration/origin.py +0 -0
  105. {gemd-2.3.2 → gemd-3.0.0}/gemd/enumeration/sample_type.py +0 -0
  106. {gemd-2.3.2 → gemd-3.0.0}/gemd/json/__init__.py +0 -0
  107. {gemd-2.3.2 → gemd-3.0.0}/gemd/json/gemd_encoder.py +0 -0
  108. {gemd-2.3.2 → gemd-3.0.0}/gemd/units/citrine_en.txt +0 -0
  109. {gemd-2.3.2 → gemd-3.0.0}/gemd/units/constants_en.txt +0 -0
  110. {gemd-2.3.2 → gemd-3.0.0}/gemd/util/__init__.py +0 -0
  111. {gemd-2.3.2 → gemd-3.0.0}/gemd.egg-info/SOURCES.txt +0 -0
  112. {gemd-2.3.2 → gemd-3.0.0}/gemd.egg-info/dependency_links.txt +0 -0
  113. {gemd-2.3.2 → gemd-3.0.0}/gemd.egg-info/top_level.txt +0 -0
  114. {gemd-2.3.2 → gemd-3.0.0}/setup.cfg +0 -0
  115. {gemd-2.3.2 → gemd-3.0.0}/tests/test_examples.py +0 -0
@@ -1,21 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemd
3
- Version: 2.3.2
3
+ Version: 3.0.0
4
4
  Summary: Python binding for Citrine's GEMD data model
5
5
  Author: Citrine Informatics
6
6
  Project-URL: Homepage, http://github.com/CitrineInformatics/gemd-python
7
7
  Classifier: Programming Language :: Python :: 3
8
- Classifier: Programming Language :: Python :: 3.9
9
8
  Classifier: Programming Language :: Python :: 3.10
10
9
  Classifier: Programming Language :: Python :: 3.11
11
10
  Classifier: Programming Language :: Python :: 3.12
12
11
  Classifier: Programming Language :: Python :: 3.13
13
- Requires-Python: >=3.9
12
+ Requires-Python: >=3.10
14
13
  Description-Content-Type: text/markdown
15
14
  License-File: LICENSE
16
15
  Requires-Dist: pint<0.25,>=0.24.4
17
16
  Requires-Dist: deprecation<3,>=2.1.0
18
- Requires-Dist: typing_extensions<5,>=4.8; python_version < "3.10"
19
17
  Dynamic: license-file
20
18
 
21
19
  # GEMD-python
@@ -0,0 +1 @@
1
+ __version__ = "3.0.0"
@@ -1,5 +1,4 @@
1
1
  # Tools to help build GEMD objects
2
- from typing import List, Union
3
2
 
4
3
  from gemd.entity.attribute import Condition, Parameter, Property, PropertyAndConditions
5
4
  from gemd.entity.attribute.base_attribute import BaseAttribute
@@ -104,10 +103,10 @@ def add_edge(
104
103
  output_material: MaterialRun,
105
104
  *,
106
105
  name: str = None,
107
- mass_fraction: Union[float, ContinuousValue] = None,
108
- number_fraction: Union[float, ContinuousValue] = None,
109
- volume_fraction: Union[float, ContinuousValue] = None,
110
- absolute_quantity: Union[int, float, ContinuousValue] = None,
106
+ mass_fraction: float | ContinuousValue = None,
107
+ number_fraction: float | ContinuousValue = None,
108
+ volume_fraction: float | ContinuousValue = None,
109
+ absolute_quantity: int | float | ContinuousValue = None,
111
110
  absolute_units: str = None,
112
111
  ) -> IngredientRun:
113
112
  """Connect two material-process spec-run quadruples with ingredients.
@@ -209,7 +208,7 @@ def add_measurement(
209
208
  *,
210
209
  name: str = None,
211
210
  template: MeasurementTemplate = None,
212
- attributes: List[BaseAttribute] = None,
211
+ attributes: list[BaseAttribute] = None,
213
212
  ) -> MeasurementRun:
214
213
  """Add a measurement run-spec set to a :class:`~gemd.entity.object.material_run.MaterialRun`.
215
214
 
@@ -264,10 +263,10 @@ def add_measurement(
264
263
 
265
264
 
266
265
  def add_attribute(
267
- target: Union[HasProperties, HasConditions, HasParameters],
268
- template: Union[PropertyTemplate, ConditionTemplate, ParameterTemplate],
269
- value: Union[BaseValue, str, float, int],
270
- ) -> Union[Property, Condition, Parameter]:
266
+ target: HasProperties | HasConditions | HasParameters,
267
+ template: PropertyTemplate | ConditionTemplate | ParameterTemplate,
268
+ value: BaseValue | str | float | int,
269
+ ) -> Property | Condition | Parameter:
271
270
  """Generate an attribute, and then add it attribute to a GEMD object.
272
271
 
273
272
  Parameters
@@ -314,9 +313,9 @@ def add_attribute(
314
313
 
315
314
 
316
315
  def make_attribute(
317
- template: Union[PropertyTemplate, ConditionTemplate, ParameterTemplate],
318
- value: Union[BaseValue, str, float, int],
319
- ) -> Union[Property, Condition, Parameter]:
316
+ template: PropertyTemplate | ConditionTemplate | ParameterTemplate,
317
+ value: BaseValue | str | float | int,
318
+ ) -> Property | Condition | Parameter:
320
319
  """Generate an Attribute and the contained Value.
321
320
 
322
321
  Parameters
@@ -350,7 +349,7 @@ def make_attribute(
350
349
  return attribute
351
350
 
352
351
 
353
- def make_value(value: Union[str, float, int], bounds: BaseBounds) -> BaseValue:
352
+ def make_value(value: str | float | int, bounds: BaseBounds) -> BaseValue:
354
353
  """Generate a Value object based upon a number or string and a particular bounds.
355
354
 
356
355
  Parameters
@@ -1,6 +1,6 @@
1
1
  """Demo representing Strehlow & Cook bandgap data with data concepts."""
2
2
 
3
- from typing import Iterable
3
+ from collections.abc import Iterable
4
4
 
5
5
  from gemd.entity.attribute.condition import Condition
6
6
  from gemd.entity.attribute.property import Property
@@ -1,5 +1,5 @@
1
1
  from abc import abstractmethod
2
- from typing import Iterable, List, Optional, Type, Union
2
+ from collections.abc import Iterable
3
3
 
4
4
  from gemd.entity.bounds_validation import WarningLevel, get_validation_level
5
5
  from gemd.entity.dict_serializable import DictSerializable, logger
@@ -37,11 +37,11 @@ class BaseAttribute(DictSerializable):
37
37
  self,
38
38
  name: str,
39
39
  *,
40
- template: Union[AttributeTemplate, LinkByUID, None] = None,
41
- origin: Union[Origin, str] = Origin.UNKNOWN,
40
+ template: AttributeTemplate | LinkByUID | None = None,
41
+ origin: Origin | str = Origin.UNKNOWN,
42
42
  value: BaseValue = None,
43
43
  notes: str = None,
44
- file_links: Optional[Union[Iterable[FileLink], FileLink]] = None,
44
+ file_links: Iterable[FileLink] | FileLink | None = None,
45
45
  ):
46
46
  self.name = name
47
47
  self.notes = notes
@@ -85,12 +85,12 @@ class BaseAttribute(DictSerializable):
85
85
  raise TypeError(f"value must be a BaseValue: {value}")
86
86
 
87
87
  @property
88
- def template(self) -> Optional[Union[AttributeTemplate, LinkByUID]]:
88
+ def template(self) -> AttributeTemplate | LinkByUID | None:
89
89
  """Get the template."""
90
90
  return self._template
91
91
 
92
92
  @template.setter
93
- def template(self, template: Optional[Union[AttributeTemplate, LinkByUID]]):
93
+ def template(self, template: AttributeTemplate | LinkByUID | None):
94
94
  """Set the template."""
95
95
  if template is None:
96
96
  self._template = None
@@ -103,7 +103,7 @@ class BaseAttribute(DictSerializable):
103
103
 
104
104
  @staticmethod
105
105
  @abstractmethod
106
- def _template_type() -> Type:
106
+ def _template_type() -> type:
107
107
  """Get the expected type of template for this object (property of child)."""
108
108
 
109
109
  @property
@@ -112,18 +112,18 @@ class BaseAttribute(DictSerializable):
112
112
  return self._origin
113
113
 
114
114
  @origin.setter
115
- def origin(self, origin: Union[Origin, str]):
115
+ def origin(self, origin: Origin | str):
116
116
  """Set the origin."""
117
117
  if origin is None:
118
118
  raise ValueError("origin must be specified (but may be `unknown`)")
119
119
  self._origin = Origin.from_str(origin, exception=True)
120
120
 
121
121
  @property
122
- def file_links(self) -> List[FileLink]:
122
+ def file_links(self) -> list[FileLink]:
123
123
  """Get the file links."""
124
124
  return self._file_links
125
125
 
126
126
  @file_links.setter
127
- def file_links(self, file_links: Optional[Union[Iterable[FileLink], FileLink]]):
127
+ def file_links(self, file_links: Iterable[FileLink] | FileLink | None):
128
128
  """Set the file links."""
129
129
  self._file_links = validate_list(file_links, FileLink)
@@ -1,5 +1,3 @@
1
- from typing import Type
2
-
3
1
  from gemd.entity.attribute.base_attribute import BaseAttribute
4
2
  from gemd.entity.template import ConditionTemplate
5
3
 
@@ -32,5 +30,5 @@ class Condition(BaseAttribute, typ="condition"):
32
30
  """
33
31
 
34
32
  @staticmethod
35
- def _template_type() -> Type:
33
+ def _template_type() -> type:
36
34
  return ConditionTemplate
@@ -1,5 +1,3 @@
1
- from typing import Type
2
-
3
1
  from gemd.entity.attribute.base_attribute import BaseAttribute
4
2
  from gemd.entity.template import ParameterTemplate
5
3
 
@@ -33,5 +31,5 @@ class Parameter(BaseAttribute, typ="parameter"):
33
31
  """
34
32
 
35
33
  @staticmethod
36
- def _template_type() -> Type:
34
+ def _template_type() -> type:
37
35
  return ParameterTemplate
@@ -1,5 +1,3 @@
1
- from typing import Type
2
-
3
1
  from gemd.entity.attribute.base_attribute import BaseAttribute
4
2
  from gemd.entity.template import PropertyTemplate
5
3
 
@@ -32,5 +30,5 @@ class Property(BaseAttribute, typ="property"):
32
30
  """
33
31
 
34
32
  @staticmethod
35
- def _template_type() -> Type:
33
+ def _template_type() -> type:
36
34
  return PropertyTemplate
@@ -1,4 +1,4 @@
1
- from typing import Iterable, List, Optional, Union
1
+ from collections.abc import Iterable
2
2
 
3
3
  from gemd.entity.attribute.condition import Condition
4
4
  from gemd.entity.attribute.property import Property
@@ -26,7 +26,7 @@ class PropertyAndConditions(DictSerializable, typ="property_and_conditions"):
26
26
  """
27
27
 
28
28
  def __init__(
29
- self, property: Property = None, conditions: Union[Iterable[Condition], Condition] = None
29
+ self, property: Property = None, conditions: Iterable[Condition] | Condition = None
30
30
  ):
31
31
  self._property = None
32
32
  self.property = property
@@ -34,7 +34,7 @@ class PropertyAndConditions(DictSerializable, typ="property_and_conditions"):
34
34
  self.conditions = conditions
35
35
 
36
36
  @property
37
- def conditions(self) -> List[Condition]:
37
+ def conditions(self) -> list[Condition]:
38
38
  """Get conditions."""
39
39
  return self._conditions
40
40
 
@@ -49,7 +49,7 @@ class PropertyAndConditions(DictSerializable, typ="property_and_conditions"):
49
49
  return self.property.name
50
50
 
51
51
  @property
52
- def template(self) -> Optional[Union[PropertyTemplate, LinkByUID]]:
52
+ def template(self) -> PropertyTemplate | LinkByUID | None:
53
53
  """Get template of attribute (use template of property)."""
54
54
  return self.property.template
55
55
 
@@ -1,6 +1,7 @@
1
1
  """Base class for all entities."""
2
2
 
3
- from typing import Dict, FrozenSet, Iterable, List, MutableMapping, Optional, Set, TypeVar, Union
3
+ from collections.abc import Iterable, MutableMapping
4
+ from typing import TypeVar
4
5
 
5
6
  from gemd.entity.case_insensitive_dict import CaseInsensitiveDict
6
7
  from gemd.entity.dict_serializable import DictSerializable
@@ -28,7 +29,7 @@ class BaseEntity(DictSerializable):
28
29
  self.uids = uids
29
30
 
30
31
  @property
31
- def tags(self) -> List[str]:
32
+ def tags(self) -> list[str]:
32
33
  """A collection of structured labels.
33
34
 
34
35
  `Tags <https://citrineinformatics.github.io/gemd-documentation/specification/tags/>`_
@@ -43,7 +44,7 @@ class BaseEntity(DictSerializable):
43
44
  self._tags = validate_list(tags, str)
44
45
 
45
46
  @property
46
- def uids(self) -> Dict[str, str]:
47
+ def uids(self) -> dict[str, str]:
47
48
  """A collection of unique IDs.
48
49
 
49
50
  Requirements for and the value of unique IDs are discussed
@@ -76,9 +77,7 @@ class BaseEntity(DictSerializable):
76
77
  """
77
78
  self.uids[scope] = uid
78
79
 
79
- def to_link(
80
- self, scope: Optional[str] = None, *, allow_fallback: bool = False
81
- ) -> LinkByUIDType:
80
+ def to_link(self, scope: str | None = None, *, allow_fallback: bool = False) -> LinkByUIDType:
82
81
  """Generate a ~gemd.entity.link_by_uid.LinkByUID for this object.
83
82
 
84
83
  Parameters
@@ -107,7 +106,7 @@ class BaseEntity(DictSerializable):
107
106
 
108
107
  return LinkByUID(scope=scope, id=uid)
109
108
 
110
- def all_dependencies(self) -> Set[Union[BaseEntityType, LinkByUIDType]]:
109
+ def all_dependencies(self) -> set[BaseEntityType | LinkByUIDType]:
111
110
  """Return a set of all immediate dependencies (no recursion)."""
112
111
  result = set()
113
112
  queue = [type(self)]
@@ -121,8 +120,8 @@ class BaseEntity(DictSerializable):
121
120
 
122
121
  @staticmethod
123
122
  def _cached_equals(
124
- this: "BaseEntity", that: "BaseEntity", *, cache: Dict[FrozenSet, Optional[bool]] = None
125
- ) -> Optional[bool]:
123
+ this: "BaseEntity", that: "BaseEntity", *, cache: dict[frozenset, bool | None] = None
124
+ ) -> bool | None:
126
125
  """Compute and stash whether two Base Entities are equal in a recursive sense.
127
126
 
128
127
  The cache uses ternary logic to communicate state. True or False indicate a completed
@@ -1,7 +1,7 @@
1
1
  """Base class for all bounds."""
2
2
 
3
3
  from abc import abstractmethod
4
- from typing import TypeVar, Union
4
+ from typing import TypeVar
5
5
 
6
6
  from gemd.entity.dict_serializable import DictSerializable
7
7
 
@@ -14,7 +14,7 @@ class BaseBounds(DictSerializable):
14
14
  """Base class for bounds, including RealBounds and CategoricalBounds."""
15
15
 
16
16
  @abstractmethod
17
- def contains(self, bounds: Union[BaseBoundsType, BaseValueType]):
17
+ def contains(self, bounds: BaseBoundsType | BaseValueType):
18
18
  """Check if another bounds is contained within this bounds.
19
19
 
20
20
  Parameters
@@ -41,7 +41,7 @@ class BaseBounds(DictSerializable):
41
41
  raise TypeError(f"{bounds} is not a Bounds object")
42
42
 
43
43
  @abstractmethod
44
- def union(self, *others: Union[BaseBoundsType, BaseValueType]) -> BaseBoundsType:
44
+ def union(self, *others: BaseBoundsType | BaseValueType) -> BaseBoundsType:
45
45
  """Return the union of this bounds and other bounds.
46
46
 
47
47
  The others list must also be the same class (e.g., categorical, real...).
@@ -61,7 +61,7 @@ class BaseBounds(DictSerializable):
61
61
  """
62
62
 
63
63
  @abstractmethod
64
- def update(self, *others: Union[BaseBoundsType, BaseValueType]):
64
+ def update(self, *others: BaseBoundsType | BaseValueType):
65
65
  """Update this bounds to include other bounds.
66
66
 
67
67
  The others list must also be the same class (e.g., categorical, real...).
@@ -1,4 +1,5 @@
1
- from typing import Any, Dict, Iterable, Optional, Set, TypeVar, Union
1
+ from collections.abc import Iterable
2
+ from typing import Any, TypeVar
2
3
 
3
4
  from gemd.entity.bounds.base_bounds import BaseBounds
4
5
  from gemd.entity.util import array_like
@@ -19,17 +20,17 @@ class CategoricalBounds(BaseBounds, typ="categorical_bounds"):
19
20
 
20
21
  """
21
22
 
22
- def __init__(self, categories: Optional[Iterable[str]] = None):
23
+ def __init__(self, categories: Iterable[str] | None = None):
23
24
  self._categories = None
24
25
  self.categories = categories
25
26
 
26
27
  @property
27
- def categories(self) -> Set[str]:
28
+ def categories(self) -> set[str]:
28
29
  """The collection of allowed categories."""
29
30
  return self._categories
30
31
 
31
32
  @categories.setter
32
- def categories(self, categories: Optional[Iterable[str]]):
33
+ def categories(self, categories: Iterable[str] | None):
33
34
  if categories is None:
34
35
  self._categories = set()
35
36
  elif isinstance(categories, array_like()):
@@ -42,7 +43,7 @@ class CategoricalBounds(BaseBounds, typ="categorical_bounds"):
42
43
  if not all(isinstance(x, str) for x in self.categories):
43
44
  raise ValueError("All the categories must be strings")
44
45
 
45
- def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool:
46
+ def contains(self, bounds: BaseBounds | BaseValueType) -> bool:
46
47
  """Check if another bounds object or value object is contained by this bounds.
47
48
 
48
49
  The other object must also be Categorical and its allowed categories must be a
@@ -74,7 +75,7 @@ class CategoricalBounds(BaseBounds, typ="categorical_bounds"):
74
75
  return bounds.categories.issubset(self.categories)
75
76
 
76
77
  def union(
77
- self, *others: Union[CategoricalBoundsType, CategoricalValueType]
78
+ self, *others: CategoricalBoundsType | CategoricalValueType
78
79
  ) -> CategoricalBoundsType:
79
80
  """Return the union of this bounds and other bounds.
80
81
 
@@ -111,7 +112,7 @@ class CategoricalBounds(BaseBounds, typ="categorical_bounds"):
111
112
  result.update(bounds.categories)
112
113
  return CategoricalBounds(result)
113
114
 
114
- def update(self, *others: Union[CategoricalBoundsType, CategoricalValueType]):
115
+ def update(self, *others: CategoricalBoundsType | CategoricalValueType):
115
116
  """Update this bounds to include other bounds.
116
117
 
117
118
  The others list must also be Categorical Bounds or Values.
@@ -126,7 +127,7 @@ class CategoricalBounds(BaseBounds, typ="categorical_bounds"):
126
127
  """
127
128
  self.categories = self.union(*others).categories
128
129
 
129
- def as_dict(self) -> Dict[str, Any]:
130
+ def as_dict(self) -> dict[str, Any]:
130
131
  """Convert bounds to a dictionary.
131
132
 
132
133
  Returns
@@ -1,6 +1,7 @@
1
1
  """Bounds a composition to have a specified set of components."""
2
2
 
3
- from typing import Iterable, Set, TypeVar, Union
3
+ from collections.abc import Iterable
4
+ from typing import TypeVar
4
5
 
5
6
  from gemd.entity.bounds.base_bounds import BaseBounds
6
7
  from gemd.entity.util import array_like
@@ -26,7 +27,7 @@ class CompositionBounds(BaseBounds, typ="composition_bounds"):
26
27
  self.components = components
27
28
 
28
29
  @property
29
- def components(self) -> Set[str]:
30
+ def components(self) -> set[str]:
30
31
  """Get the collection of the components that are allowed in the composition."""
31
32
  return self._components
32
33
 
@@ -45,7 +46,7 @@ class CompositionBounds(BaseBounds, typ="composition_bounds"):
45
46
  if not all(isinstance(x, str) for x in self.components):
46
47
  raise ValueError("All the components must be strings")
47
48
 
48
- def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool:
49
+ def contains(self, bounds: BaseBounds | BaseValueType) -> bool:
49
50
  """Check if another bounds or value object is contained by this bounds.
50
51
 
51
52
  The other object must also be a Composition and its components must be a subset of
@@ -76,7 +77,7 @@ class CompositionBounds(BaseBounds, typ="composition_bounds"):
76
77
  return bounds.components.issubset(self.components)
77
78
 
78
79
  def union(
79
- self, *others: Union[CompositionBoundsType, CompositionValueType]
80
+ self, *others: CompositionBoundsType | CompositionValueType
80
81
  ) -> CompositionBoundsType:
81
82
  """Return the union of this bounds and other bounds.
82
83
 
@@ -113,7 +114,7 @@ class CompositionBounds(BaseBounds, typ="composition_bounds"):
113
114
  result.update(bounds.components)
114
115
  return CompositionBounds(result)
115
116
 
116
- def update(self, *others: Union[CompositionBoundsType, CompositionValueType]):
117
+ def update(self, *others: CompositionBoundsType | CompositionValueType):
117
118
  """Update this bounds to include other bounds.
118
119
 
119
120
  The others list must also be Composition Bounds or Values.
@@ -1,7 +1,7 @@
1
1
  """Bounds an integer to be between two values."""
2
2
 
3
3
  from math import isfinite
4
- from typing import TypeVar, Union
4
+ from typing import TypeVar
5
5
 
6
6
  from gemd.entity.bounds.base_bounds import BaseBounds
7
7
 
@@ -64,7 +64,7 @@ class IntegerBounds(BaseBounds, typ="integer_bounds"):
64
64
  )
65
65
  self._upper_bound = int(value)
66
66
 
67
- def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool:
67
+ def contains(self, bounds: BaseBounds | BaseValueType) -> bool:
68
68
  """Check if another bounds or value object is a subset of this range.
69
69
 
70
70
  The other object must also be an Integer and its lower and upper bound must *both*
@@ -94,7 +94,7 @@ class IntegerBounds(BaseBounds, typ="integer_bounds"):
94
94
 
95
95
  return bounds.lower_bound >= self.lower_bound and bounds.upper_bound <= self.upper_bound
96
96
 
97
- def union(self, *others: Union[IntegerBoundsType, IntegerValueType]) -> IntegerBoundsType:
97
+ def union(self, *others: IntegerBoundsType | IntegerValueType) -> IntegerBoundsType:
98
98
  """Return the union of this bounds and other bounds.
99
99
 
100
100
  The others list must also be Integer Bounds or Values.
@@ -132,7 +132,7 @@ class IntegerBounds(BaseBounds, typ="integer_bounds"):
132
132
  upper = bounds.upper_bound
133
133
  return IntegerBounds(lower_bound=lower, upper_bound=upper)
134
134
 
135
- def update(self, *others: Union[IntegerBoundsType, IntegerValueType]):
135
+ def update(self, *others: IntegerBoundsType | IntegerValueType):
136
136
  """Update this bounds to include other bounds.
137
137
 
138
138
  The others list must also be Integer Bounds or Values.
@@ -3,7 +3,7 @@
3
3
  In the future, this may include substructural restrictions.
4
4
  """
5
5
 
6
- from typing import TypeVar, Union
6
+ from typing import TypeVar
7
7
 
8
8
  from gemd.entity.bounds.base_bounds import BaseBounds
9
9
 
@@ -16,7 +16,7 @@ MolecularValueType = TypeVar("MolecularValueType", bound="MolecularValue") # no
16
16
  class MolecularStructureBounds(BaseBounds, typ="molecular_structure_bounds"):
17
17
  """Molecular bounds, with no component or substructural restrictions (yet)."""
18
18
 
19
- def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool:
19
+ def contains(self, bounds: BaseBounds | BaseValueType) -> bool:
20
20
  """Check if another bounds or value object is contained by this bounds.
21
21
 
22
22
  The other object must also be or type Molecular. There are no other
@@ -46,9 +46,7 @@ class MolecularStructureBounds(BaseBounds, typ="molecular_structure_bounds"):
46
46
 
47
47
  return True
48
48
 
49
- def union(
50
- self, *others: Union[MolecularBoundsType, MolecularValueType]
51
- ) -> MolecularBoundsType:
49
+ def union(self, *others: MolecularBoundsType | MolecularValueType) -> MolecularBoundsType:
52
50
  """Return the union of this bounds and other bounds.
53
51
 
54
52
  The others list must also be Molecular Structure Bounds or Values.
@@ -79,7 +77,7 @@ class MolecularStructureBounds(BaseBounds, typ="molecular_structure_bounds"):
79
77
  )
80
78
  return MolecularStructureBounds()
81
79
 
82
- def update(self, *others: Union[MolecularBoundsType, MolecularValueType]):
80
+ def update(self, *others: MolecularBoundsType | MolecularValueType):
83
81
  """Update this bounds to include other bounds.
84
82
 
85
83
  The others list must also be Molecular Structure Bounds or Values.
@@ -1,7 +1,7 @@
1
1
  """Bound a real number to be between two values."""
2
2
 
3
3
  from math import isfinite
4
- from typing import TypeVar, Union
4
+ from typing import TypeVar
5
5
 
6
6
  import gemd.units as units
7
7
  from gemd.entity.bounds.base_bounds import BaseBounds
@@ -85,7 +85,7 @@ class RealBounds(BaseBounds, typ="real_bounds"):
85
85
  )
86
86
  self._default_units = units.parse_units(default_units, return_unit=False)
87
87
 
88
- def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool:
88
+ def contains(self, bounds: BaseBounds | BaseValueType) -> bool:
89
89
  """Check if another bounds or value object is a subset of this range.
90
90
 
91
91
  The other object must also be Real and its lower and upper bound must *both*
@@ -121,7 +121,7 @@ class RealBounds(BaseBounds, typ="real_bounds"):
121
121
 
122
122
  return bounds.lower_bound >= lower and bounds.upper_bound <= upper
123
123
 
124
- def union(self, *others: Union[RealBoundsType, ContinuousValueType]) -> RealBoundsType:
124
+ def union(self, *others: RealBoundsType | ContinuousValueType) -> RealBoundsType:
125
125
  """Return the union of this bounds and other bounds.
126
126
 
127
127
  The others list must also be Real Bounds or Values.
@@ -163,7 +163,7 @@ class RealBounds(BaseBounds, typ="real_bounds"):
163
163
  upper = bnd_hi
164
164
  return RealBounds(lower_bound=lower, upper_bound=upper, default_units=unit_)
165
165
 
166
- def update(self, *others: Union[RealBoundsType, ContinuousValueType]):
166
+ def update(self, *others: RealBoundsType | ContinuousValueType):
167
167
  """Update this bounds to include other bounds.
168
168
 
169
169
  The others list must also be Real Bounds or Values.
@@ -1,11 +1,15 @@
1
- from typing import Any, Mapping, Optional, Sequence, Tuple
1
+ from collections.abc import Mapping, Sequence
2
+ from typing import Any, TypeVar, overload
2
3
 
3
4
  __all__ = ["CaseInsensitiveDict"]
4
5
 
5
- _RaiseKeyError = object() # singleton for no-default behavior
6
+ _VT = TypeVar("_VT")
7
+ _T = TypeVar("_T")
6
8
 
9
+ _RaiseKeyError: Any = object() # singleton for no-default behavior
7
10
 
8
- class CaseInsensitiveDict(dict):
11
+
12
+ class CaseInsensitiveDict(dict[str, _VT]):
9
13
  """A dictionary in which the keys are case-insensitive.
10
14
 
11
15
  It is initialized the same way as a typical dict, but the values can be accessed without
@@ -29,10 +33,19 @@ class CaseInsensitiveDict(dict):
29
33
  for key in self:
30
34
  self._register_key(key)
31
35
 
32
- def __getitem__(self, key: str) -> Any:
36
+ def __getitem__(self, key: str) -> _VT:
33
37
  return super().__getitem__(self.lowercase_dict[key.lower()])
34
38
 
35
- def get(self, key: str, default: Any = None) -> Any:
39
+ @overload
40
+ def get(self, key: str, default: None = None, /) -> _VT | None: ...
41
+
42
+ @overload
43
+ def get(self, key: str, default: _VT, /) -> _VT: ...
44
+
45
+ @overload
46
+ def get(self, key: str, default: _T, /) -> _VT | _T: ...
47
+
48
+ def get(self, key: str, default: Any = None, /) -> Any:
36
49
  """Get the value for a given case-insensitive key.
37
50
 
38
51
  Parameters
@@ -55,7 +68,7 @@ class CaseInsensitiveDict(dict):
55
68
  else:
56
69
  return default
57
70
 
58
- def __setitem__(self, key: str, value: Any) -> None:
71
+ def __setitem__(self, key: str, value: _VT) -> None:
59
72
  self._register_key(key)
60
73
  super().__setitem__(key, value)
61
74
 
@@ -72,7 +85,16 @@ class CaseInsensitiveDict(dict):
72
85
  super().clear()
73
86
  self.lowercase_dict.clear()
74
87
 
75
- def pop(self, key: str, default=_RaiseKeyError) -> Any:
88
+ @overload
89
+ def pop(self, key: str, /) -> _VT: ...
90
+
91
+ @overload
92
+ def pop(self, key: str, default: _VT, /) -> _VT: ...
93
+
94
+ @overload
95
+ def pop(self, key: str, default: _T, /) -> _VT | _T: ...
96
+
97
+ def pop(self, key: str, default: Any = _RaiseKeyError, /) -> Any:
76
98
  """Remove and return the value for a given key from the dictionary.
77
99
 
78
100
  If key is in the dictionary, remove it and return its value, else return default.
@@ -103,7 +125,7 @@ class CaseInsensitiveDict(dict):
103
125
  del self.lowercase_dict[key.lower()]
104
126
  return val
105
127
 
106
- def popitem(self) -> Tuple:
128
+ def popitem(self) -> tuple[str, _VT]:
107
129
  """Remove and return a (key, value) pair from the dictionary.
108
130
 
109
131
  popitem() is useful to destructively iterate over a dictionary, as often used
@@ -115,7 +137,7 @@ class CaseInsensitiveDict(dict):
115
137
 
116
138
  Returns
117
139
  -------
118
- Tuple(str, Any)
140
+ tuple[str, Any]
119
141
  The key-value pair
120
142
 
121
143
  """
@@ -123,7 +145,7 @@ class CaseInsensitiveDict(dict):
123
145
  del self.lowercase_dict[result[0].lower()]
124
146
  return result
125
147
 
126
- def copy(self) -> "CaseInsensitiveDict":
148
+ def copy(self) -> "CaseInsensitiveDict[_VT]":
127
149
  """Return a shallow copy of the dictionary.
128
150
 
129
151
  Returns
@@ -134,7 +156,7 @@ class CaseInsensitiveDict(dict):
134
156
  """
135
157
  return CaseInsensitiveDict(super().copy())
136
158
 
137
- def update(self, mapping: Optional[Mapping[str, Any]] = None, **kwargs) -> None:
159
+ def update(self, mapping: Mapping[str, Any] | None = None, **kwargs) -> None:
138
160
  """Update the dictionary with the key/value pairs from other, overwriting existing keys.
139
161
 
140
162
  update() accepts either another dictionary object or an iterable of