diff --git a/docs/source/_static/favicon.png b/docs/source/_static/favicon.png new file mode 100644 index 00000000..62a362ea Binary files /dev/null and b/docs/source/_static/favicon.png differ diff --git a/docs/source/_static/logo.png b/docs/source/_static/logo.png new file mode 100644 index 00000000..9481d88e Binary files /dev/null and b/docs/source/_static/logo.png differ diff --git a/docs/source/conf.py b/docs/source/conf.py index a6c8a9f9..94b60730 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,9 +10,10 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # +import gemd import os import sys -sys.path.insert(0, os.path.abspath('../../gemd')) +sys.path.insert(0, os.path.abspath('../..')) # -- Project information ----------------------------------------------------- @@ -21,8 +22,10 @@ copyright = '2020, Citrine Informatics' author = 'Citrine Informatics' -# The full version, including alpha/beta/rc tags -release = '0.0.0' +# The short X.Y version. +version = gemd.__version__ +# The full version, including alpha/beta/rc tags. +release = gemd.__version__ # -- General configuration --------------------------------------------------- @@ -43,8 +46,9 @@ # See: https://github.com/sphinx-contrib/apidoc apidoc_module_dir = '../../gemd' apidoc_output_dir = 'reference' -apidoc_excluded_paths = ['tests'] +apidoc_excluded_paths = ['tests', '*impl*'] apidoc_separate_modules = True +apidoc_toc_file = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -76,6 +80,9 @@ # autodoc_mock_imports allows Sphinx to ignore any external modules listed in the array autodoc_mock_imports = [] +html_favicon = '_static/favicon.png' +html_logo = '_static/logo.png' html_theme_options = { - "sticky_navigation": False -} \ No newline at end of file + 'sticky_navigation': False, + 'logo_only': True +} diff --git a/docs/source/depth/index.rst b/docs/source/depth/index.rst deleted file mode 100644 index 11e06753..00000000 --- a/docs/source/depth/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -====================== -In depth documentation -====================== - -.. toctree:: - :maxdepth: 2 - - unit_parsing - serialization \ No newline at end of file diff --git a/docs/source/depth/unit_parsing.rst b/docs/source/depth/unit_parsing.rst index 7abd1bdb..d7430b3c 100644 --- a/docs/source/depth/unit_parsing.rst +++ b/docs/source/depth/unit_parsing.rst @@ -7,8 +7,13 @@ By default, Pint supports a larger set of units than the Citrine Platform. Therefore, we include a custom unit definition file in gemd-python: `citrine_en.txt`_. This file contains the most commonly used units and will grow over time. +In support of common patterns in materials science, we permit including scaling factors in a unit of measure. +For example, industrial researchers may have recorded historical data as ``g / 2.5 cm``. +While this could be converted a simple SI expression, that would prevent researchers from representing the data +as originally reported, thus creating a potential source of error during the input process. + Requests for support of additional units can be made by opening an issue in the `gemd-python repository`_ on github. -.. _Pint: https://pint.readthedocs.io/en/0.9/ +.. _Pint: https://pint.readthedocs.io/en/0.20/ .. _citrine_en.txt: https://github.com/CitrineInformatics/gemd-python/blob/main/gemd/units/citrine_en.txt .. _GEMD-python repository: https://github.com/CitrineInformatics/gemd-python diff --git a/docs/source/index.rst b/docs/source/index.rst index fdc129a9..a49d07df 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,11 +6,28 @@ Welcome to the GEMD-Python Documentation! =================================================== -``gemd`` is the Python implementation of the Citrine data model, the full documentation of which -can be found `here `_. +This site documents the Python implementation of the Graphical Expression of Materials Data (GEMD) model. +GEMD is an open source data format developed by `Citrine Informatics `_ for representing +data in materials in a `FAIR `_ and transformable manner. +Documentation of the underlying data model can be found `here `_. To learn about the details of specific classes, please see the module index. +Installation +------------ + +The latest release can be installed via `pip`: + +.. code:: bash + + pip install gemd + +or a specific version can be installed, for example: + +.. code:: bash + + pip install gemd==1.17.1 + Table of Contents ----------------- @@ -18,11 +35,17 @@ Table of Contents :maxdepth: 2 :numbered: 4 - depth/index + depth/unit_parsing + depth/serialization -Indices and tables +Indices ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` + +.. toctree:: + :maxdepth: 1 + + reference/gemd diff --git a/docs/source/modules.rst b/docs/source/modules.rst deleted file mode 100644 index f96a8607..00000000 --- a/docs/source/modules.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. toctree:: - :maxdepth: 4 - - setup diff --git a/docs/source/setup.rst b/docs/source/setup.rst deleted file mode 100644 index 552eb49d..00000000 --- a/docs/source/setup.rst +++ /dev/null @@ -1,7 +0,0 @@ -setup module -============ - -.. automodule:: setup - :members: - :undoc-members: - :show-inheritance: diff --git a/gemd/__init__.py b/gemd/__init__.py index c1ab8ccf..b8ae0b5a 100644 --- a/gemd/__init__.py +++ b/gemd/__init__.py @@ -1,5 +1,5 @@ """Data concepts library.""" -# flake8: noqa +from .__version__ import __version__ # noqa: F401 from .entity import Condition, Parameter, Property, PropertyAndConditions, \ CategoricalBounds, CompositionBounds, IntegerBounds, \ MolecularStructureBounds, RealBounds, \ @@ -12,7 +12,7 @@ UniformInteger, DiscreteCategorical, NominalCategorical, \ EmpiricalFormula, NominalComposition, InChI, Smiles, \ LinkByUID, \ - FileLink + FileLink # noqa: F401 __all__ = ["Condition", "Parameter", "Property", "PropertyAndConditions", "CategoricalBounds", "CompositionBounds", "IntegerBounds", diff --git a/gemd/__version__.py b/gemd/__version__.py new file mode 100644 index 00000000..4a7bff54 --- /dev/null +++ b/gemd/__version__.py @@ -0,0 +1 @@ +__version__ = "1.18.1" diff --git a/gemd/builders/__init__.py b/gemd/builders/__init__.py index 2b6884c9..9b21387f 100644 --- a/gemd/builders/__init__.py +++ b/gemd/builders/__init__.py @@ -1,2 +1,6 @@ # flake8: noqa from .impl import make_node, add_edge, add_measurement, add_attribute, make_attribute, make_value + +__all__ = [ + "make_node", "add_edge", "add_measurement", "add_attribute", "make_attribute", "make_value" +] diff --git a/gemd/builders/impl.py b/gemd/builders/impl.py index 430f76b7..395755d9 100644 --- a/gemd/builders/impl.py +++ b/gemd/builders/impl.py @@ -18,6 +18,10 @@ from typing import Union, List +__all__ = [ + "make_node", "add_edge", "add_measurement", "add_attribute", "make_attribute", "make_value" +] + def make_node(name: str, *, @@ -30,19 +34,22 @@ def make_node(name: str, Parameters ---------- name: str - Name of the MaterialRun and MaterialSpec. + Name of the :class:`~gemd.entity.object.material_run.MaterialRun` + and :class:`~gemd.entity.object.material_spec.MaterialSpec`. process_name: str - Name of the ProcessRun and ProcessSpec. Defaults to - `process_template.name` if `process_template` is defined, else `name`. - process_template: ProcessTemplate - ProcessTemplate for the quadruple. - material_template: MaterialTemplate - MaterialTemplate for the quadruple. + Name of the :class:`~gemd.entity.object.process_run.ProcessRun` + and :class:`~gemd.entity.object.process_spec.ProcessSpec`. Defaults to + :attr:`process_template.name` if `process_template` is defined, else `name`. + process_template: ~gemd.entity.template.process_template.ProcessTemplate + :class:`~gemd.entity.template.process_template.ProcessTemplate` for the quadruple. + material_template: ~gemd.entity.template.material_template.MaterialTemplate + :class:`~gemd.entity.template.material_template.MaterialTemplate` for the quadruple. Returns -------- - MaterialRun - A MaterialRun with linked processes, specs and templates + ~gemd.entity.object.material_run.MaterialRun + A :class:`~gemd.entity.object.material_run.MaterialRun` with linked processes, + specs and templates """ if process_name is None: @@ -90,28 +97,45 @@ def add_edge(input_material: MaterialRun, Parameters ---------- - input_material: MaterialRun - The `material` for the returned IngredientRun - output_material: MaterialRun - The `process` for the returned IngredientRun will be - `output_material.process` + input_material: ~gemd.entity.object.material_run.MaterialRun + The :attr:`~gemd.entity.object.ingredient_run.IngredientRun.material` + for the returned + :class:`~gemd.entity.object.ingredient_run.IngredientRun` + output_material: ~gemd.entity.object.material_run.MaterialRun + The :attr:`~gemd.entity.object.ingredient_run.IngredientRun.process` + for the returned + :class:`~gemd.entity.object.ingredient_run.IngredientRun` + will be `output_material.process` name: str The ingredient name. Defaults to `input_material.name`. - mass_fraction: float or ContinuousValue - The mass fraction of the Ingredient Run. 0 <= x <= 1 - number_fraction: float or ContinuousValue - The number fraction of the Ingredient Run. 0 <= x <= 1 - volume_fraction: float or ContinuousValue - The volume fraction of the Ingredient Run. 0 <= x <= 1 - absolute_quantity: float or ContinuousValue - The absolute quantity. 0 <= x + mass_fraction: float or ~gemd.entity.value.continuous_value.ContinuousValue + The :attr:`~gemd.entity.object.ingredient_run.IngredientRun.mass_fraction` + of the returned + :class:`~gemd.entity.object.ingredient_run.IngredientRun`.` + 0 <= x <= 1 + number_fraction: float or ~gemd.entity.value.continuous_value.ContinuousValue + The :attr:`~gemd.entity.object.ingredient_run.IngredientRun.number_fraction` + of the returned + :class:`~gemd.entity.object.ingredient_run.IngredientRun`. + 0 <= x <= 1 + volume_fraction: float or ~gemd.entity.value.continuous_value.ContinuousValue + The :attr:`~gemd.entity.object.ingredient_run.IngredientRun.volume_fraction` + of the returned + :class:`~gemd.entity.object.ingredient_run.IngredientRun`. + 0 <= x <= 1 + absolute_quantity: float or ~gemd.entity.value.continuous_value.ContinuousValue + The :attr:`~gemd.entity.object.ingredient_run.IngredientRun.absolute_quantity` + of the returned + :class:`~gemd.entity.object.ingredient_run.IngredientRun`. + 0 <= x absolute_units: str The absolute units. Required if absolute_quantity is provided as a float Returns -------- - IngredientRun - A IngredientRun with linked processes, specs and materials + ~gemd.entity.object.ingredient_run.IngredientRun + A :class:`~gemd.entity.object.ingredient_run.IngredientRun` + with linked processes, specs and materials """ output_spec = output_material.spec @@ -171,24 +195,33 @@ def add_measurement(material: MaterialRun, attributes: List[BaseAttribute] = None, ) -> MeasurementRun: """ - Add a measurement run-spec set to a MaterialRun. + Add a measurement run-spec set to a :class:`~gemd.entity.object.material_run.MaterialRun`. Parameters ---------- - material: MaterialRun - The `material` for the returned MeasurementRun + material: ~gemd.entity.object.material_run.MaterialRun + The :attr:`~gemd.entity.object.measurement_run.MeasurementRun.material` + for the returned + :class:`~gemd.entity.object.measurement_run.MeasurementRun` name: str - The name of the measurement. Defaults to - `template.name` if `template` is defined. - template: MeasurementTemplate - The MeasurementTemplate. + The :attr:`~gemd.entity.object.measurement_run.MeasurementRun.name` + of the measurement. Defaults to `template.name` if `template` is defined. + template: ~gemd.entity.template.measurement_template.MeasurementTemplate + The :attr:`~gemd.entity.object.measurement_run.MeasurementRun.template` + for the returned + :class:`~gemd.entity.object.measurement_run.MeasurementRun` attributes: List[BaseAttribute] - Attributes you want associated with this MeasurementRun. + Attributes you want associated with this + :class:`~gemd.entity.object.measurement_run.MeasurementRun`. These can be + :class:`Conditions `, + :class:`Parameters `, + and/or :class:`Properties `. Returns -------- - MeasurementRun - A MeasurementRun with linked material, spec and template + ~gemd.entity.object.measurement_run.MeasurementRun + A :class:`~gemd.entity.object.measurement_run.MeasurementRun` + with linked material, spec and template """ if name is None: @@ -226,10 +259,10 @@ def add_attribute(target: Union[HasProperties, HasConditions, HasParameters], target: BaseObject The object to attach the attribute to template: AttributeTemplate - The AttributeTemplate for the attribute. - value: Union[BaseValue, str, float, int] - The value for the attribute. Accepts any GEMD Value type, or will - attempt to generate an appropriate Value given a str, float or int. + The :attr:`~BaseAttribute.template` for the attribute. + value: BaseValue, str, float, or int + The :attr:`~BaseAttribute.value` for the attribute. Accepts any GEMD Value type, or will + attempt to generate an appropriate :class:`BaseValue` subclass given a str, float or int. Returns -------- @@ -272,9 +305,9 @@ def make_attribute(template: Union[PropertyTemplate, ConditionTemplate, Paramete Parameters ---------- template: AttributeTemplate - The AttributeTemplate for the attribute. - value: Union[BaseValue, str, float, int] - The value for the attribute. Accepts any GEMD Value type, or will + The :attr:`~BaseAttribute.template` for the attribute. + value: BaseValue, str, float, or int + The :attr:`~BaseAttribute.value` for the attribute. Accepts any GEMD Value type, or will attempt to generate an appropriate Value given a str, float or int. Returns @@ -307,7 +340,7 @@ def make_value(value: Union[str, float, int], Parameters ---------- - value: Union[str, float, int] + value: str, float, or int The primitive type to wrap in a Value bounds: BaseBounds The bounds type to determine which value type we want to coerce the value into diff --git a/gemd/demo/cake.py b/gemd/demo/cake.py index 055e3ecc..fb266340 100644 --- a/gemd/demo/cake.py +++ b/gemd/demo/cake.py @@ -25,6 +25,10 @@ from gemd.util.impl import recursive_foreach +__all__ = [ + "change_scope", "get_demo_scope", "get_template_scope", "import_toothpick_picture", + "make_cake_templates", "make_cake_spec", "make_cake" +] # For now, module constant, though likely this should get promoted to a package level DEMO_SCOPE = 'citrine-demo' diff --git a/gemd/demo/strehlow_and_cook.py b/gemd/demo/strehlow_and_cook.py index 389b9ab9..bc6f768a 100644 --- a/gemd/demo/strehlow_and_cook.py +++ b/gemd/demo/strehlow_and_cook.py @@ -37,6 +37,11 @@ FULL_TABLE = "strehlow_and_cook.pif" SMALL_TABLE = "strehlow_and_cook_small.pif" +__all__ = [ + "import_table", "minimal_subset", "make_templates", "make_strehlow_objects", + "make_strehlow_table", "make_display_table" +] + def import_table(filename=SMALL_TABLE): """Return the deserialized JSON table.""" @@ -398,6 +403,7 @@ def make_display_table(structured): (CSV of scalar values) based upon some standard assumptions about how it should be displayed. :param structured: A structured table, such as generated by make_strehlow_table + :return """ table = [[]] diff --git a/gemd/entity/attribute/base_attribute.py b/gemd/entity/attribute/base_attribute.py index 3f103907..c38aa026 100644 --- a/gemd/entity/attribute/base_attribute.py +++ b/gemd/entity/attribute/base_attribute.py @@ -1,7 +1,7 @@ from gemd.entity.dict_serializable import DictSerializable, logger from gemd.entity.template.attribute_template import AttributeTemplate from gemd.entity.value.base_value import BaseValue -from gemd.enumeration import Origin +from gemd.enumeration.origin import Origin from gemd.entity.setters import validate_list from gemd.entity.file_link import FileLink from gemd.entity.link_by_uid import LinkByUID @@ -21,16 +21,15 @@ class BaseAttribute(DictSerializable): Required name of the attribute. Each attribute within an object must have a unique name. notes: str Optional free-form notes about the attribute. - value: :py:class:`BaseValue ` + value: BaseValue The value of the attribute. - template: :class:`AttributeTemplate \ - ` + template: AttributeTemplate Attribute template that defines the allowed bounds of this attribute. If a template and value are both present then the value must be within the template bounds. - origin: str + origin: str or ~gemd.enumeration.origin.Origin The origin of the attribute. Must be one of "measured", "predicted", "summary", "specified", "computed", or "unknown." Default is "unknown." - file_links: List[FileLink] + file_links: List[~gemd.entity.file_link.FileLink] Links to files associated with the attribute. """ @@ -69,11 +68,12 @@ def _check(template: AttributeTemplate, value: BaseValue): @property def value(self) -> BaseValue: - """Get value.""" + """Get the value.""" return self._value @value.setter def value(self, value: BaseValue): + """Set the value.""" if value is None: self._value = None elif isinstance(value, BaseValue): @@ -85,11 +85,12 @@ def value(self, value: BaseValue): @property def template(self) -> Optional[Union[AttributeTemplate, LinkByUID]]: - """Get template.""" + """Get the template.""" return self._template @template.setter def template(self, template: Optional[Union[AttributeTemplate, LinkByUID]]): + """Set the template.""" if template is None: self._template = None elif isinstance(template, (self._template_type(), LinkByUID)): @@ -107,20 +108,22 @@ def _template_type() -> Type: @property def origin(self) -> Origin: - """Get origin.""" + """Get the origin.""" return self._origin @origin.setter def origin(self, origin: Union[Origin, str]): + """Set the origin.""" if origin is None: raise ValueError("origin must be specified (but may be `unknown`)") self._origin = Origin.from_str(origin, exception=True) @property def file_links(self) -> List[FileLink]: - """Get file links.""" + """Get the file links.""" return self._file_links @file_links.setter def file_links(self, file_links: Optional[Union[Iterable[FileLink], FileLink]]): + """Set the file links.""" self._file_links = validate_list(file_links, FileLink) diff --git a/gemd/entity/attribute/condition.py b/gemd/entity/attribute/condition.py index 90315d1b..aff09882 100644 --- a/gemd/entity/attribute/condition.py +++ b/gemd/entity/attribute/condition.py @@ -3,6 +3,8 @@ from typing import Type +__all__ = ["Condition"] + class Condition(BaseAttribute, typ="condition"): """ @@ -17,16 +19,15 @@ class Condition(BaseAttribute, typ="condition"): Required name of the attribute. Each attribute within an object must have a unique name. notes: str Optional free-form notes about the attribute. - value: :class:`BaseValue ` + value: ~gemd.entity.value.base_value.BaseValue The value of the attribute. - template: :class:`AttributeTemplate \ - ` + template: ~gemd.entity.template.attribute_template.AttributeTemplate Attribute template that defines the allowed bounds of this attribute. If a template and value are both present then the value must be within the template bounds. origin: str The origin of the attribute. Must be one of "measured", "predicted", "summary", "specified", "computed", or "unknown." Default is "unknown." - file_links: List[:class:`FileLink `] + file_links: List[~gemd.entity.file_link.FileLink] Links to files associated with the attribute. """ diff --git a/gemd/entity/attribute/parameter.py b/gemd/entity/attribute/parameter.py index 5d8615e3..d8bf136c 100644 --- a/gemd/entity/attribute/parameter.py +++ b/gemd/entity/attribute/parameter.py @@ -3,6 +3,8 @@ from typing import Type +__all__ = ["Parameter"] + class Parameter(BaseAttribute, typ="parameter"): """ @@ -18,16 +20,15 @@ class Parameter(BaseAttribute, typ="parameter"): Required name of the attribute. Each attribute within an object must have a unique name. notes: str Optional free-form notes about the attribute. - value: :class:`BaseValue ` + value: ~gemd.entity.value.base_value.BaseValue The value of the attribute. - template: :class:`AttributeTemplate \ - ` + template: ~gemd.entity.template.attribute_template.AttributeTemplate Attribute template that defines the allowed bounds of this attribute. If a template and value are both present then the value must be within the template bounds. origin: str The origin of the attribute. Must be one of "measured", "predicted", "summary", "specified", "computed", or "unknown." Default is "unknown." - file_links: List[:class:`FileLink `] + file_links: List[~gemd.entity.file_link.FileLink] Links to files associated with the attribute. """ diff --git a/gemd/entity/attribute/property.py b/gemd/entity/attribute/property.py index 6528fc92..bdc0277c 100644 --- a/gemd/entity/attribute/property.py +++ b/gemd/entity/attribute/property.py @@ -3,6 +3,8 @@ from typing import Type +__all__ = ["Property"] + class Property(BaseAttribute, typ="property"): """ @@ -17,16 +19,15 @@ class Property(BaseAttribute, typ="property"): Required name of the attribute. Each attribute within an object must have a unique name. notes: str Optional free-form notes about the attribute. - value: :class:`BaseValue ` + value: ~gemd.entity.value.base_value.BaseValue The value of the attribute. - template: :class:`AttributeTemplate \ - ` + template: ~gemd.entity.template.attribute_template.AttributeTemplate Attribute template that defines the allowed bounds of this attribute. If a template and value are both present then the value must be within the template bounds. origin: str The origin of the attribute. Must be one of "measured", "predicted", "summary", "specified", "computed", or "unknown." Default is "unknown." - file_links: List[:class:`FileLink `] + file_links: List[~gemd.entity.file_link.FileLink] Links to files associated with the attribute. """ diff --git a/gemd/entity/attribute/property_and_conditions.py b/gemd/entity/attribute/property_and_conditions.py index 192d5af9..040f77da 100644 --- a/gemd/entity/attribute/property_and_conditions.py +++ b/gemd/entity/attribute/property_and_conditions.py @@ -8,6 +8,8 @@ from typing import Optional, Union, Iterable, List +__all__ = ["PropertyAndConditions"] + class PropertyAndConditions(DictSerializable, typ="property_and_conditions"): """ @@ -17,9 +19,9 @@ class PropertyAndConditions(DictSerializable, typ="property_and_conditions"): Parameters ---------- - property: :class:`Property ` + property: ~gemd.entity.attribute.property.Property A property attribute - conditions: List[:class:`Condition `] + conditions: List[~gemd.entity.attribute.condition.Condition] An optional list of conditions associated with this property. """ diff --git a/gemd/entity/base_entity.py b/gemd/entity/base_entity.py index c1d72289..06d169e8 100644 --- a/gemd/entity/base_entity.py +++ b/gemd/entity/base_entity.py @@ -1,30 +1,20 @@ """Base class for all entities.""" -from typing import Optional, Union, Iterable, List, Set, FrozenSet, Mapping, Dict +from typing import TypeVar, Optional, Union, Iterable, List, Set, FrozenSet, MutableMapping, Dict from gemd.entity.dict_serializable import DictSerializable from gemd.entity.has_dependencies import HasDependencies from gemd.entity.case_insensitive_dict import CaseInsensitiveDict from gemd.entity.setters import validate_list +__all__ = ["BaseEntity"] +BaseEntityType = TypeVar("BaseEntityType", bound="BaseEntity") +LinkByUIDType = TypeVar("LinkByUIDType", bound="LinkByUID") # noqa: F821 -class BaseEntity(DictSerializable): - """ - Base class for any entity, which includes objects and templates. - - Parameters - ---------- - uids: Map[str, str] - A collection of - `unique IDs `_. - tags: List[str] - `Tags `_ - are hierarchical strings that store information about an entity. They can be used - for filtering and discoverability. - """ +class BaseEntity(DictSerializable): + """Base class for any entity, which includes objects and templates.""" - def __init__(self, uids: Mapping[str, str], tags: Iterable[str]): + def __init__(self, uids: MutableMapping[str, str], tags: Iterable[str]): self._tags = None self.tags = tags @@ -33,23 +23,37 @@ def __init__(self, uids: Mapping[str, str], tags: Iterable[str]): @property def tags(self) -> List[str]: - """Get the tags.""" + """A collection of structured labels. + + `Tags `_ + are hierarchical strings that store information about an entity. They can be used + for filtering and discoverability. + """ return self._tags @tags.setter def tags(self, tags: Iterable[str]): + """Set the tags.""" self._tags = validate_list(tags, str) @property - def uids(self) -> Mapping[str, str]: - """Get the uids.""" + def uids(self) -> Dict[str, str]: + """ + A collection of unique IDs. + + Requirements for and the value of unique IDs are discussed + `here `_. + + """ return self._uids @uids.setter - def uids(self, uids: Mapping[str, str]): + def uids(self, uids: MutableMapping[str, str]): + """Set the uids.""" if uids is None: self._uids = CaseInsensitiveDict() - elif isinstance(uids, Mapping): + elif isinstance(uids, MutableMapping): self._uids = CaseInsensitiveDict(**uids) else: self._uids = CaseInsensitiveDict(**{uids[0]: uids[1]}) @@ -71,9 +75,10 @@ def add_uid(self, scope: str, uid: str): def to_link(self, scope: Optional[str] = None, *, - allow_fallback: bool = False) -> 'LinkByUID': # noqa: F821 + allow_fallback: bool = False + ) -> LinkByUIDType: """ - Generate a LinkByUID for this object. + Generate a ~gemd.entity.link_by_uid.LinkByUID for this object. Parameters ---------- @@ -84,7 +89,7 @@ def to_link(self, Returns ------- - LinkByUID + ~gemd.entity.link_by_uid.LinkByUID """ from gemd.entity.link_by_uid import LinkByUID @@ -100,7 +105,7 @@ def to_link(self, return LinkByUID(scope=scope, id=uid) - def all_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def all_dependencies(self) -> Set[Union[BaseEntityType, LinkByUIDType]]: """Return a set of all immediate dependencies (no recursion).""" result = set() queue = [type(self)] @@ -113,10 +118,11 @@ def all_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F8 return result @staticmethod - def _cached_equals(this: 'BaseEntity', - that: 'BaseEntity', + def _cached_equals(this: "BaseEntity", + that: "BaseEntity", *, - cache: Dict[FrozenSet, Optional[bool]] = None) -> Optional[bool]: + cache: Dict[FrozenSet, Optional[bool]] = None + ) -> Optional[bool]: """ Compute and stash whether two Base Entities are equal in a recursive sense. diff --git a/gemd/entity/bounds/base_bounds.py b/gemd/entity/bounds/base_bounds.py index fb6b4236..93281264 100644 --- a/gemd/entity/bounds/base_bounds.py +++ b/gemd/entity/bounds/base_bounds.py @@ -1,28 +1,33 @@ """Base class for all bounds.""" from abc import abstractmethod -from typing import Union +from typing import TypeVar, Union from gemd.entity.dict_serializable import DictSerializable +__all__ = ["BaseBounds"] +BaseBoundsType = TypeVar("BaseBoundsType", bound="BaseBounds") +BaseValueType = TypeVar("BaseValueType", bound="BaseValue") # noqa: F821 + class BaseBounds(DictSerializable): """Base class for bounds, including RealBounds and CategoricalBounds.""" @abstractmethod - def contains(self, bounds: Union["BaseBounds", "BaseValue"]): # noqa: F821 + def contains(self, bounds: Union[BaseBoundsType, BaseValueType]): """ Check if another bounds is contained within this bounds. Parameters ---------- - bounds: Union[BaseBounds, BaseValue] + bounds: BaseBounds or BaseValue Other bounds object to check. If it's a Value object, check against - the smallest compatible bounds, as returned by the + the smallest compatible bounds, as returned by the Value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- bool - True if any value that validates true for bounds also validates true for this + True if all values valid for `bounds` are also valid for this object """ from gemd.entity.value.base_value import BaseValue @@ -36,7 +41,7 @@ def contains(self, bounds: Union["BaseBounds", "BaseValue"]): # noqa: F821 raise TypeError('{} is not a Bounds object'.format(bounds)) @abstractmethod - def union(self, *others: Union["BaseBounds", "BaseValue"]) -> "BaseBounds": # noqa: F821 + def union(self, *others: Union[BaseBoundsType, BaseValueType]) -> BaseBoundsType: """ Return the union of this bounds and other bounds. @@ -44,8 +49,10 @@ def union(self, *others: Union["BaseBounds", "BaseValue"]) -> "BaseBounds": # n Parameters ---------- - others: Union[BaseBounds, BaseValue] - Other bounds or value objects to include. + others: BaseBounds or BaseValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -53,10 +60,9 @@ def union(self, *others: Union["BaseBounds", "BaseValue"]) -> "BaseBounds": # n The union of this bounds and the passed bounds """ - pass # pragma: no cover @abstractmethod - def update(self, *others: Union["BaseBounds", "BaseValue"]): # noqa: F821 + def update(self, *others: Union[BaseBoundsType, BaseValueType]): """ Update this bounds to include other bounds. @@ -64,8 +70,9 @@ def update(self, *others: Union["BaseBounds", "BaseValue"]): # noqa: F821 Parameters ---------- - others: Union[BaseBounds, BaseValue] - Other bounds or value objects to include. + others: BaseBounds or BaseValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. """ - pass # pragma: no cover diff --git a/gemd/entity/bounds/categorical_bounds.py b/gemd/entity/bounds/categorical_bounds.py index bad59205..20be8acf 100644 --- a/gemd/entity/bounds/categorical_bounds.py +++ b/gemd/entity/bounds/categorical_bounds.py @@ -1,8 +1,12 @@ -"""A restricted set of categories.""" +from typing import TypeVar, Any, Union, Set, Optional, Iterable, Dict + from gemd.entity.bounds.base_bounds import BaseBounds from gemd.entity.util import array_like -from typing import Union, Set, Optional, Iterable +__all__ = ["CategoricalBounds"] +CategoricalBoundsType = TypeVar("CategoricalBoundsType", bound="CategoricalBounds") +BaseValueType = TypeVar("BaseValueType", bound="BaseValue") # noqa: F821 +CategoricalValueType = TypeVar("CategoricalValueType", bound="CategoricalValue") # noqa: F821 class CategoricalBounds(BaseBounds, typ="categorical_bounds"): @@ -22,7 +26,7 @@ def __init__(self, categories: Optional[Iterable[str]] = None): @property def categories(self) -> Set[str]: - """Get the set of categories.""" + """The collection of allowed categories.""" return self._categories @categories.setter @@ -39,17 +43,20 @@ def categories(self, categories: Optional[Iterable[str]]): if not all(isinstance(x, str) for x in self.categories): raise ValueError("All the categories must be strings") - def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F821 + def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool: """ - Check if another bounds object or value objects is contained by this bounds. + Check if another bounds object or value object is contained by this bounds. The other object must also be Categorical and its allowed categories must be a subset of this bounds's allowed categories. Parameters ---------- - bounds: Union[BaseBounds, BaseValue] - Other bounds or value object to check. + bounds: BaseBounds or BaseValue + Other bounds or value object to check. If it's a Value object, check against + the smallest compatible bounds, as returned by the Value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. + Returns ------- @@ -69,8 +76,8 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 return bounds.categories.issubset(self.categories) def union(self, - *others: Union["CategoricalBounds", "CategoricalValue"] # noqa: F821 - ) -> "CategoricalBounds": # noqa: F821 + *others: Union[CategoricalBoundsType, CategoricalValueType] + ) -> CategoricalBoundsType: """ Return the union of this bounds and other bounds. @@ -78,8 +85,10 @@ def union(self, Parameters ---------- - others: Union[CategoricalBounds, CategoricalValue] - Other bounds or value objects to include. + others: CategoricalBounds or ~gemd.value.categorical_value.CategoricalValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -102,7 +111,7 @@ def union(self, result.update(bounds.categories) return CategoricalBounds(result) - def update(self, *others: Union["CategoricalBounds", "CategoricalValue"]): # noqa: F821 + def update(self, *others: Union[CategoricalBoundsType, CategoricalValueType]): """ Update this bounds to include other bounds. @@ -110,13 +119,15 @@ def update(self, *others: Union["CategoricalBounds", "CategoricalValue"]): # no Parameters ---------- - others: Union[CategoricalBounds, CategoricalValue] - Other bounds or value objects to include. + others: CategoricalBounds or ~gemd.entity.value.categorical_value.CategoricalValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. """ self.categories = self.union(*others).categories - def as_dict(self): + def as_dict(self) -> Dict[str, Any]: """ Convert bounds to a dictionary. diff --git a/gemd/entity/bounds/composition_bounds.py b/gemd/entity/bounds/composition_bounds.py index db399d5c..3b2ff8fd 100644 --- a/gemd/entity/bounds/composition_bounds.py +++ b/gemd/entity/bounds/composition_bounds.py @@ -2,7 +2,12 @@ from gemd.entity.bounds.base_bounds import BaseBounds from gemd.entity.util import array_like -from typing import Union +from typing import TypeVar, Union, Set, Iterable + +__all__ = ["CompositionBounds"] +CompositionBoundsType = TypeVar("CompositionBoundsType", bound="CompositionBounds") +BaseValueType = TypeVar("BaseValueType", bound="BaseValue") # noqa: F821 +CompositionValueType = TypeVar("CompositionValueType", bound="CompositionValue") # noqa: F821 class CompositionBounds(BaseBounds, typ="composition_bounds"): @@ -21,12 +26,13 @@ def __init__(self, components=None): self.components = components @property - def components(self): - """Get the allowed components.""" + def components(self) -> Set[str]: + """Get the collection of the components that are allowed in the composition.""" return self._components @components.setter - def components(self, value): + def components(self, value: Iterable[str]): + """Set collection of the components that are allowed in the composition.""" if value is None: self._components = set() elif isinstance(value, array_like()): @@ -39,7 +45,7 @@ def components(self, value): if not all(isinstance(x, str) for x in self.components): raise ValueError("All the components must be strings") - def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F821 + def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool: """ Check if another bounds or value object is contained by this bounds. @@ -48,8 +54,10 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 Parameters ---------- - bounds: Union[BaseBounds, BaseValue] - Other object to check. + bounds: BaseBounds or BaseValue + Other object to check. If it's a Value object, check against + the smallest compatible bounds, as returned by the Value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -69,8 +77,8 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 return bounds.components.issubset(self.components) def union(self, - *others: Union["CompositionBounds", "CompositionValue"] # noqa: F821 - ) -> "CompositionBounds": # noqa: F821 + *others: Union[CompositionBoundsType, CompositionValueType] + ) -> CompositionBoundsType: """ Return the union of this bounds and other bounds. @@ -78,12 +86,14 @@ def union(self, Parameters ---------- - others: Union[CompositionBounds, CompositionValue] - Other bounds or value objects to include. + others: CompositionBounds or ~gemd.entity.value.compositional_value.CompositionValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- - CategoricalBounds + CompositionBounds The union of this bounds and the passed bounds """ @@ -102,16 +112,18 @@ def union(self, result.update(bounds.components) return CompositionBounds(result) - def update(self, *others: Union["CompositionBounds", "CompositionValue"]): # noqa: F821 + def update(self, *others: Union[CompositionBoundsType, CompositionValueType]): """ Update this bounds to include other bounds. - The others list must also be Categorical Bounds or Values. + The others list must also be Composition Bounds or Values. Parameters ---------- - others: Union[CategoricalBounds, CategoricalValue] - Other bounds or value objects to include. + others: CompositionBounds or ~gemd.entity.value.compositional_value.CompositionValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. """ self.components = self.union(*others).components diff --git a/gemd/entity/bounds/integer_bounds.py b/gemd/entity/bounds/integer_bounds.py index 212fffda..bd27b991 100644 --- a/gemd/entity/bounds/integer_bounds.py +++ b/gemd/entity/bounds/integer_bounds.py @@ -1,14 +1,26 @@ """Bounds an integer to be between two values.""" from math import isfinite -from typing import Union +from typing import TypeVar, Union from gemd.entity.bounds.base_bounds import BaseBounds __all__ = ["IntegerBounds"] +IntegerBoundsType = TypeVar("IntegerBoundsType", bound="IntegerBounds") +BaseValueType = TypeVar("BaseValueType", bound="BaseValue") # noqa: F821 +IntegerValueType = TypeVar("IntegerValueType", bound="IntegerValue") # noqa: F821 class IntegerBounds(BaseBounds, typ="integer_bounds"): - """Bounded subset of the integers, parameterized by a lower and upper bound.""" + """ + Bounded subset of the integers, parameterized by a lower and upper bound. + + Parameters + ---------- + lower_bound: int + The lower endpoint (inclusive) of the permitted range. + upper_bound: int + The upper endpoint (inclusive) of the permitted range. + """ def __init__(self, lower_bound: int, upper_bound: int): self._lower_bound = None @@ -47,7 +59,7 @@ def upper_bound(self, value: int): f"greater than or equal to lower bound ({self.lower_bound})") self._upper_bound = int(value) - def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F821 + def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool: """ Check if another bounds or value object is a subset of this range. @@ -56,8 +68,10 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 Parameters ---------- - bounds: Union[BaseBounds, BaseValue] - Other bounds or value object to check. + bounds: BaseBounds or BaseValue + Other bounds or value object to check. If it's a Value object, check against + the smallest compatible bounds, as returned by the Value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -77,8 +91,8 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 return bounds.lower_bound >= self.lower_bound and bounds.upper_bound <= self.upper_bound def union(self, - *others: Union["IntegerBounds", "IntegerValue"] # noqa: F821 - ) -> "IntegerBounds": # noqa: F821 + *others: Union[IntegerBoundsType, IntegerValueType] + ) -> IntegerBoundsType: """ Return the union of this bounds and other bounds. @@ -86,8 +100,10 @@ def union(self, Parameters ---------- - others: Union[IntegerBounds, IntegerValue] - Other bounds or value objects to include. + others: IntegerBounds or ~gemd.entity.value.integer_value.IntegerValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -113,16 +129,18 @@ def union(self, upper = bounds.upper_bound return IntegerBounds(lower_bound=lower, upper_bound=upper) - def update(self, *others: Union["IntegerBounds", "IntegerValue"]): # noqa: F821 + def update(self, *others: Union[IntegerBoundsType, IntegerValueType]): """ Update this bounds to include other bounds. - The others list must also be Categorical Bounds or Values. + The others list must also be Integer Bounds or Values. Parameters ---------- - others: Union[IntegerBounds, IntegerValue] - Other bounds or value objects to include. + others: IntegerBounds or ~gemd.entity.value.integer_value.IntegerValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. """ result = self.union(*others) diff --git a/gemd/entity/bounds/molecular_structure_bounds.py b/gemd/entity/bounds/molecular_structure_bounds.py index de08b369..4586531e 100644 --- a/gemd/entity/bounds/molecular_structure_bounds.py +++ b/gemd/entity/bounds/molecular_structure_bounds.py @@ -5,13 +5,18 @@ """ from gemd.entity.bounds.base_bounds import BaseBounds -from typing import Union +from typing import TypeVar, Union + +__all__ = ["MolecularStructureBounds"] +MolecularBoundsType = TypeVar("MolecularBoundsType", bound="MolecularStructureBounds") +BaseValueType = TypeVar("BaseValueType", bound="BaseValue") # noqa: F821 +MolecularValueType = TypeVar("MolecularValueType", bound="MolecularValue") # noqa: F821 class MolecularStructureBounds(BaseBounds, typ="molecular_structure_bounds"): """Molecular bounds, with no component or substructural restrictions (yet).""" - def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F821 + def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool: """ Check if another bounds or value object is contained by this bounds. @@ -20,8 +25,10 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 Parameters ---------- - bounds: Union[BaseBounds, BaseValue] - Other bounds or value object to check. + bounds: BaseBounds or BaseValue + Other bounds or value object to check. If it's a Value object, check against + the smallest compatible bounds, as returned by the Value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -41,8 +48,8 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 return True def union(self, - *others: Union["MolecularStructureBounds", "MolecularValue"] # noqa: F821 - ) -> "MolecularStructureBounds": # noqa: F821 + *others: Union[MolecularBoundsType, MolecularValueType] + ) -> MolecularBoundsType: """ Return the union of this bounds and other bounds. @@ -50,13 +57,15 @@ def union(self, Parameters ---------- - others: Union[MolecularStructureBounds, MolecularValue] + others: MolecularStructureBounds or ~gemd.entity.value.molecular_value.MolecularValue Other bounds or value objects to include. Returns ------- - CategoricalBounds - The union of this bounds and the passed bounds + MolecularStructureBounds + The union of this bounds and the passed bounds. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. """ from gemd.entity.value.molecular_value import MolecularValue @@ -69,7 +78,7 @@ def union(self, f"expected molecular structure, found {misses}") return MolecularStructureBounds() - def update(self, *others: Union["MolecularStructureBounds", "MolecularValue"]): # noqa: F821 + def update(self, *others: Union[MolecularBoundsType, MolecularValueType]): """ Update this bounds to include other bounds. @@ -77,8 +86,10 @@ def update(self, *others: Union["MolecularStructureBounds", "MolecularValue"]): Parameters ---------- - others: Union[MolecularStructureBounds, MolecularValue] - Other bounds or value objects to include. + others: MolecularStructureBounds or ~gemd.entity.value.molecular_value.MolecularValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. """ pass # This is a no-op for Molecular structure diff --git a/gemd/entity/bounds/real_bounds.py b/gemd/entity/bounds/real_bounds.py index 786888e8..041d0159 100644 --- a/gemd/entity/bounds/real_bounds.py +++ b/gemd/entity/bounds/real_bounds.py @@ -1,13 +1,27 @@ """Bound a real number to be between two values.""" from math import isfinite -from typing import Union +from typing import TypeVar, Union from gemd.entity.bounds.base_bounds import BaseBounds import gemd.units as units +__all__ = ["RealBounds"] +RealBoundsType = TypeVar("RealBoundsType", bound="RealBounds") +BaseValueType = TypeVar("BaseValueType", bound="BaseValue") # noqa: F821 +ContinuousValueType = TypeVar("ContinuousValueType", bound="ContinuousValue") # noqa: F821 + class RealBounds(BaseBounds, typ="real_bounds"): - """Bounded subset of the real numbers, parameterized by a lower and upper bound.""" + """ + Bounded subset of the real numbers, parameterized by a lower and upper bound. + + Parameters + ---------- + lower_bound: float + The lower endpoint (inclusive) of the permitted range. + upper_bound: float + The upper endpoint (inclusive) of the permitted range. + """ def __init__(self, lower_bound: float, upper_bound: float, default_units: str): self._default_units = None @@ -66,7 +80,7 @@ def default_units(self, default_units: str): "Use an empty string for a dimensionless quantity.") self._default_units = units.parse_units(default_units, return_unit=False) - def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F821 + def contains(self, bounds: Union[BaseBounds, BaseValueType]) -> bool: """ Check if another bounds or value object is a subset of this range. @@ -77,8 +91,10 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 Parameters ---------- - bounds: Union[BaseBounds, BaseValue] - Other bounds or value object to check. + bounds: BaseBounds or BaseValue + Other bounds or value object to check. If it's a Value object, check against + the smallest compatible bounds, as returned by the Value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -101,7 +117,9 @@ def contains(self, bounds: Union[BaseBounds, "BaseValue"]) -> bool: # noqa: F82 return bounds.lower_bound >= lower and bounds.upper_bound <= upper - def union(self, *others: Union["RealBounds", "ContinuousValue"]) -> "RealBounds": # noqa: F821 + def union(self, + *others: Union[RealBoundsType, ContinuousValueType] + ) -> RealBoundsType: """ Return the union of this bounds and other bounds. @@ -109,8 +127,10 @@ def union(self, *others: Union["RealBounds", "ContinuousValue"]) -> "RealBounds" Parameters ---------- - others: Union[RealBounds, ContinuousValue] - Other bounds or value objects to include. + others: RealBounds or ContinuousValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. Returns ------- @@ -140,7 +160,7 @@ def union(self, *others: Union["RealBounds", "ContinuousValue"]) -> "RealBounds" upper = bnd_hi return RealBounds(lower_bound=lower, upper_bound=upper, default_units=unit_) - def update(self, *others: Union["RealBounds", "ContinuousValue"]): # noqa: F821 + def update(self, *others: Union[RealBoundsType, ContinuousValueType]): """ Update this bounds to include other bounds. @@ -148,8 +168,10 @@ def update(self, *others: Union["RealBounds", "ContinuousValue"]): # noqa: F821 Parameters ---------- - others: Union[RealBounds, ContinuousValue] - Other bounds or value objects to include. + others: RealBounds or ContinuousValue + Other bounds or value objects to include. If they're Value objects, + increase by the smallest compatible bounds, as returned by the value's + :func:`~gemd.entity.base_bounds.BaseBounds._to_bounds` method. """ result = self.union(*others) diff --git a/gemd/entity/bounds_validation.py b/gemd/entity/bounds_validation.py index 328254f1..3b8c039b 100644 --- a/gemd/entity/bounds_validation.py +++ b/gemd/entity/bounds_validation.py @@ -1,6 +1,8 @@ from enum import IntEnum from contextlib import contextmanager +__all__ = ["WarningLevel", "get_validation_level", "set_validation_level", "validation_level"] + class WarningLevel(IntEnum): """ diff --git a/gemd/entity/case_insensitive_dict.py b/gemd/entity/case_insensitive_dict.py index ad9bba29..6aac2b3d 100644 --- a/gemd/entity/case_insensitive_dict.py +++ b/gemd/entity/case_insensitive_dict.py @@ -1,5 +1,7 @@ from typing import Tuple, Sequence, Any, Mapping, Optional +__all__ = ["CaseInsensitiveDict"] + _RaiseKeyError = object() # singleton for no-default behavior diff --git a/gemd/entity/dict_serializable.py b/gemd/entity/dict_serializable.py index 02ff6290..664af86b 100644 --- a/gemd/entity/dict_serializable.py +++ b/gemd/entity/dict_serializable.py @@ -6,6 +6,8 @@ import functools from typing import TypeVar, Union, Iterable, List, Mapping, Dict, Set, Any +__all__ = ["DictSerializable"] + # There are some weird (probably resolvable) errors during object cloning if this is an # instance variable of DictSerializable. logger = getLogger(__name__) @@ -123,7 +125,7 @@ def dump(self) -> Dict[str, Any]: return json.loads(encoder.raw_dumps(self)) @staticmethod - def build(d: Mapping[str, Any]) -> "DictSerializable": + def build(d: Mapping[str, Any]) -> DictSerializableType: """ Build an object from a JSON dictionary. diff --git a/gemd/entity/file_link.py b/gemd/entity/file_link.py index f22ada95..24e971af 100644 --- a/gemd/entity/file_link.py +++ b/gemd/entity/file_link.py @@ -1,6 +1,8 @@ """Represents a link to an external file.""" from gemd.entity.dict_serializable import DictSerializable +__all__ = ["FileLink"] + class FileLink(DictSerializable, typ="file_link"): """ diff --git a/gemd/entity/has_dependencies.py b/gemd/entity/has_dependencies.py index 87b6f4e0..ce57b0ee 100644 --- a/gemd/entity/has_dependencies.py +++ b/gemd/entity/has_dependencies.py @@ -1,11 +1,15 @@ """For entities that have dependencies.""" from abc import ABC, abstractmethod -from typing import Union, Set +from typing import TypeVar, Union, Set + +__all__ = ["HasDependencies"] +BaseEntityType = TypeVar("BaseEntityType", bound="BaseEntity") # noqa: F821 +LinkByUIDType = TypeVar("LinkByUIDType", bound="LinkByUID") # noqa: F821 class HasDependencies(ABC): """Mix-in trait for objects that reference other objects.""" @abstractmethod - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntityType, LinkByUIDType]]: """All dependencies (objects) that this class introduces.""" diff --git a/gemd/entity/link_by_uid.py b/gemd/entity/link_by_uid.py index bec0b045..27302685 100644 --- a/gemd/entity/link_by_uid.py +++ b/gemd/entity/link_by_uid.py @@ -1,9 +1,13 @@ """A unique id that stands in for a data object.""" +from typing import TypeVar import uuid from warnings import warn from gemd.entity.dict_serializable import DictSerializable +__all__ = ["LinkByUID"] +BaseEntityType = TypeVar("BaseEntityType", bound="BaseEntity") # noqa: F821 + class LinkByUID(DictSerializable, typ="link_by_uid"): """ @@ -27,7 +31,7 @@ def __repr__(self): return str({"scope": self.scope, "id": self.id}) @classmethod - def from_entity(cls, entity, name=None, *, scope=None): + def from_entity(cls, entity: BaseEntityType, name=None, *, scope=None): """ Create LinkByUID from in-memory object. diff --git a/gemd/entity/object/base_object.py b/gemd/entity/object/base_object.py index 4020e12e..6078e83c 100644 --- a/gemd/entity/object/base_object.py +++ b/gemd/entity/object/base_object.py @@ -6,6 +6,8 @@ from typing import Optional, Union, Iterable, List, Mapping +__all__ = ["BaseObject"] + class BaseObject(BaseEntity): """ @@ -27,7 +29,7 @@ class BaseObject(BaseEntity): for filtering and discoverability. notes: str, optional Long-form notes about the object. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. """ @@ -61,16 +63,17 @@ def _attribute_has_setter(cls, name: str) -> bool: @property def name(self) -> str: - """Get name.""" + """Name of the object.""" return self._name @name.setter def name(self, name: str): + """Set the name.""" self._name = validate_str(name) @property def file_links(self) -> List[FileLink]: - """Get file links.""" + """Links to associated files, with resource paths into the files API.""" return self._file_links @file_links.setter diff --git a/gemd/entity/object/has_conditions.py b/gemd/entity/object/has_conditions.py index e0287407..8be1bb14 100644 --- a/gemd/entity/object/has_conditions.py +++ b/gemd/entity/object/has_conditions.py @@ -1,5 +1,7 @@ """For entities that have conditions.""" +from gemd.entity.base_entity import BaseEntity from gemd.entity.has_dependencies import HasDependencies +from gemd.entity.link_by_uid import LinkByUID from gemd.entity.object.has_template_check_generator import HasTemplateCheckGenerator from gemd.entity.template.has_condition_templates import HasConditionTemplates from gemd.entity.attribute.condition import Condition @@ -8,16 +10,11 @@ from typing import Union, Iterable, List, Set from abc import ABC +__all__ = ["HasConditions"] -class HasConditions(HasTemplateCheckGenerator, HasDependencies, ABC): - """Mixin-trait for entities that include conditions. - - Parameters - ---------- - conditions: List[:class:`Condition `] - A list of conditions associated with this entity. - """ +class HasConditions(HasTemplateCheckGenerator, HasDependencies, ABC): + """Mixin-trait for entities that include conditions.""" def __init__(self, conditions: Union[Condition, Iterable[Condition]]): self._conditions = None @@ -25,7 +22,7 @@ def __init__(self, conditions: Union[Condition, Iterable[Condition]]): @property def conditions(self) -> List[Condition]: - """Get a list of the conditions.""" + """A list of conditions associated with this entity.""" return self._conditions @conditions.setter @@ -34,6 +31,6 @@ def conditions(self, conditions: Union[Condition, Iterable[Condition]]): checker = self._generate_template_check(HasConditionTemplates.validate_condition) self._conditions = validate_list(conditions, Condition, trigger=checker) - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntity, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {cond.template for cond in self.conditions if cond.template is not None} diff --git a/gemd/entity/object/has_material.py b/gemd/entity/object/has_material.py index 7a9d5f5b..dd8c326a 100644 --- a/gemd/entity/object/has_material.py +++ b/gemd/entity/object/has_material.py @@ -1,11 +1,14 @@ """For entities that have specs.""" +from gemd.entity.base_entity import BaseEntity from gemd.entity.has_dependencies import HasDependencies -from gemd.entity.object.base_object import BaseObject from gemd.entity.link_by_uid import LinkByUID +from gemd.entity.object.base_object import BaseObject from abc import ABC, abstractmethod from typing import Union, Set +__all__ = ["HasMaterial"] + class HasMaterial(HasDependencies, ABC): """Mix-in trait for objects that can be assigned materials.""" @@ -20,6 +23,6 @@ def material(self) -> Union[BaseObject, LinkByUID]: def material(self, spec: Union[BaseObject, LinkByUID]): """Set the material.""" - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntity, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {self.material} if self.material is not None else set() diff --git a/gemd/entity/object/has_parameters.py b/gemd/entity/object/has_parameters.py index 28a18e67..3343c470 100644 --- a/gemd/entity/object/has_parameters.py +++ b/gemd/entity/object/has_parameters.py @@ -1,5 +1,7 @@ """For entities that have parameters.""" +from gemd.entity.base_entity import BaseEntity from gemd.entity.has_dependencies import HasDependencies +from gemd.entity.link_by_uid import LinkByUID from gemd.entity.object.has_template_check_generator import HasTemplateCheckGenerator from gemd.entity.template.has_parameter_templates import HasParameterTemplates from gemd.entity.attribute.parameter import Parameter @@ -8,16 +10,11 @@ from typing import Union, Iterable, List, Set from abc import ABC +__all__ = ["HasParameters"] -class HasParameters(HasTemplateCheckGenerator, HasDependencies, ABC): - """Mixin-trait for entities that include parameters. - - Parameters - ---------- - parameters: List[:class:`Parameter `] - A list of parameters associated with this entity. - """ +class HasParameters(HasTemplateCheckGenerator, HasDependencies, ABC): + """Mixin-trait for entities that include parameters.""" def __init__(self, parameters: Union[Parameter, Iterable[Parameter]]): self._parameters = None @@ -25,7 +22,7 @@ def __init__(self, parameters: Union[Parameter, Iterable[Parameter]]): @property def parameters(self) -> List[Parameter]: - """Get the list of parameters.""" + """A list of parameters associated with this entity.""" return self._parameters @parameters.setter @@ -34,6 +31,6 @@ def parameters(self, parameters: Union[Parameter, Iterable[Parameter]]): checker = self._generate_template_check(HasParameterTemplates.validate_parameter) self._parameters = validate_list(parameters, Parameter, trigger=checker) - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntity, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {param.template for param in self.parameters if param.template is not None} diff --git a/gemd/entity/object/has_process.py b/gemd/entity/object/has_process.py index d26b05d8..9f686e68 100644 --- a/gemd/entity/object/has_process.py +++ b/gemd/entity/object/has_process.py @@ -1,11 +1,14 @@ """For entities that have specs.""" +from gemd.entity.base_entity import BaseEntity from gemd.entity.has_dependencies import HasDependencies -from gemd.entity.object.base_object import BaseObject from gemd.entity.link_by_uid import LinkByUID +from gemd.entity.object.base_object import BaseObject from abc import abstractmethod from typing import Union, Set +__all__ = ["HasProcess"] + class HasProcess(HasDependencies): """Mix-in trait for objects that can be assigned materials.""" @@ -20,6 +23,6 @@ def process(self) -> Union[BaseObject, LinkByUID]: def process(self, process: Union[BaseObject, LinkByUID]): """Set the process.""" - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntity, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {self.process} if self.process is not None else set() diff --git a/gemd/entity/object/has_properties.py b/gemd/entity/object/has_properties.py index d247db9e..28341af0 100644 --- a/gemd/entity/object/has_properties.py +++ b/gemd/entity/object/has_properties.py @@ -1,5 +1,7 @@ """For entities that have properties.""" +from gemd.entity.base_entity import BaseEntity from gemd.entity.has_dependencies import HasDependencies +from gemd.entity.link_by_uid import LinkByUID from gemd.entity.object.has_template_check_generator import HasTemplateCheckGenerator from gemd.entity.template.has_property_templates import HasPropertyTemplates from gemd.entity.attribute.property import Property @@ -8,16 +10,11 @@ from typing import Union, Iterable, List, Set from abc import ABC +__all__ = ["HasProperties"] -class HasProperties(HasTemplateCheckGenerator, HasDependencies, ABC): - """Mixin-trait for entities that include properties. - - Parameters - ---------- - properties: List[:class:`Property `] - A list of properties associated with this entity - """ +class HasProperties(HasTemplateCheckGenerator, HasDependencies, ABC): + """Mixin-trait for entities that include properties.""" def __init__(self, properties: Union[Property, Iterable[Property]]): self._properties = None @@ -25,7 +22,7 @@ def __init__(self, properties: Union[Property, Iterable[Property]]): @property def properties(self) -> List[Property]: - """Get a list of the properties.""" + """A list of properties associated with this entity.""" return self._properties @properties.setter @@ -34,6 +31,6 @@ def properties(self, properties: Union[Property, Iterable[Property]]): checker = self._generate_template_check(HasPropertyTemplates.validate_property) self._properties = validate_list(properties, Property, trigger=checker) - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntity, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {prop.template for prop in self.properties if prop.template is not None} diff --git a/gemd/entity/object/has_quantities.py b/gemd/entity/object/has_quantities.py index bc7ea8ff..5c366eb3 100644 --- a/gemd/entity/object/has_quantities.py +++ b/gemd/entity/object/has_quantities.py @@ -7,26 +7,11 @@ from gemd.entity.bounds_validation import get_validation_level, WarningLevel from gemd.entity.dict_serializable import logger +__all__ = ["HasQuantities"] + class HasQuantities(object): - """Mixin-trait that includes the mass, volume, number fraction, and absolute quantity. - - Parameters - ---------- - mass_fraction: :class:`ContinuousValue \ - `, optional - The mass fraction of the quantity. - volume_fraction: :class:`ContinuousValue \ - `, optional - The volume fraction of the quantity. - number_fraction: :class:`ContinuousValue \ - `, optional - The number fraction of the quantity. - absolute_quantity: :class:`ContinuousValue \ - `, optional - The absolute quantity of the quantity. - - """ + """Mixin-trait that includes the mass, volume, number fraction, and absolute quantity.""" def __init__(self, *, mass_fraction: ContinuousValue = None, @@ -60,7 +45,7 @@ def _check(value: BaseValue): @property def mass_fraction(self) -> ContinuousValue: - """Get mass fraction.""" + """The mass fraction of the material.""" return self._mass_fraction @mass_fraction.setter @@ -75,7 +60,7 @@ def mass_fraction(self, mass_fraction: ContinuousValue): @property def volume_fraction(self) -> ContinuousValue: - """Get volume fraction.""" + """The volume fraction of the material.""" return self._volume_fraction @volume_fraction.setter @@ -90,7 +75,7 @@ def volume_fraction(self, volume_fraction: ContinuousValue): @property def number_fraction(self) -> ContinuousValue: - """Get number fraction.""" + """The number fraction (commonly called mole fraction) of the material.""" return self._number_fraction @number_fraction.setter @@ -105,7 +90,7 @@ def number_fraction(self, number_fraction: ContinuousValue): @property def absolute_quantity(self) -> ContinuousValue: - """Get absolute quantity.""" + """The absolute quantity of the material.""" return self._absolute_quantity @absolute_quantity.setter diff --git a/gemd/entity/object/has_source.py b/gemd/entity/object/has_source.py index a4b04bb1..f14dcc5c 100644 --- a/gemd/entity/object/has_source.py +++ b/gemd/entity/object/has_source.py @@ -1,17 +1,11 @@ """For entities that have parameters.""" from gemd.entity.source.performed_source import PerformedSource +__all__ = ["HasSource"] -class HasSource(object): - """Mixin-trait for entities that include sources (data provenance). - - Parameters - ---------- - source: :class:`PerformedSource\ - `, optional - Information about the person who performed the run and when. - """ +class HasSource(object): + """Mixin-trait for entities that include sources (data provenance).""" def __init__(self, source: PerformedSource): self._source = None @@ -19,7 +13,7 @@ def __init__(self, source: PerformedSource): @property def source(self) -> PerformedSource: - """Get the list of parameters.""" + """Information about the person who performed the run and when.""" return self._source @source.setter diff --git a/gemd/entity/object/has_spec.py b/gemd/entity/object/has_spec.py index d91ca213..7772cde3 100644 --- a/gemd/entity/object/has_spec.py +++ b/gemd/entity/object/has_spec.py @@ -1,22 +1,18 @@ """For entities that have specs.""" +from gemd.entity.base_entity import BaseEntity from gemd.entity.has_dependencies import HasDependencies +from gemd.entity.link_by_uid import LinkByUID from gemd.entity.object.has_template import HasTemplate from gemd.entity.template.base_template import BaseTemplate -from gemd.entity.link_by_uid import LinkByUID from abc import abstractmethod from typing import Optional, Union, Set, Type +__all__ = ["HasSpec"] -class HasSpec(HasDependencies): - """Mix-in trait for objects that can be assigned specs. - Parameters - ---------- - spec: :class:`Has_Template ` - A spec, which expresses the anticipated or aspirational behavior of this object. - - """ +class HasSpec(HasDependencies): + """Mix-in trait for objects that can be assigned specs.""" def __init__(self, spec: Union[HasTemplate, LinkByUID] = None): self._spec = None @@ -24,7 +20,7 @@ def __init__(self, spec: Union[HasTemplate, LinkByUID] = None): @property def spec(self) -> Union[HasTemplate, LinkByUID]: - """Get the spec.""" + """A spec, which expresses the anticipated or aspirational behavior of this object.""" return self._spec @spec.setter @@ -51,6 +47,6 @@ def template(self) -> Optional[Union[BaseTemplate, LinkByUID]]: else: return None - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntity, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {self.spec} if self.spec is not None else set() diff --git a/gemd/entity/object/has_template.py b/gemd/entity/object/has_template.py index c968f9fa..c38662e1 100644 --- a/gemd/entity/object/has_template.py +++ b/gemd/entity/object/has_template.py @@ -1,21 +1,17 @@ """For entities that have templates.""" +from gemd.entity.base_entity import BaseEntity from gemd.entity.has_dependencies import HasDependencies -from gemd.entity.template.base_template import BaseTemplate from gemd.entity.link_by_uid import LinkByUID +from gemd.entity.template.base_template import BaseTemplate from abc import abstractmethod from typing import Optional, Union, Set, Type +__all__ = ["HasTemplate"] -class HasTemplate(HasDependencies): - """Mix-in trait for objects that can be assigned templates. - Parameters - ---------- - template: :class:`BaseTemplate ` - A template that defines the allowed values. - - """ +class HasTemplate(HasDependencies): + """Mix-in trait for objects that can be assigned templates.""" def __init__(self, template: Optional[Union[BaseTemplate, LinkByUID]] = None): self._template = None @@ -28,7 +24,7 @@ def _template_type() -> Type: @property def template(self) -> Optional[Union[BaseTemplate, LinkByUID]]: - """Get the template.""" + """A template that defines the allowed values.""" return self._template @template.setter @@ -42,6 +38,6 @@ def template(self, template: Optional[Union[BaseTemplate, LinkByUID]]): raise TypeError(f"Template must be a {self._template_type()} or LinkByUID, " f"not {type(template)}") - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntity, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {self.template} if self.template is not None else set() diff --git a/gemd/entity/object/has_template_check_generator.py b/gemd/entity/object/has_template_check_generator.py index 6fa49dee..23b936ba 100644 --- a/gemd/entity/object/has_template_check_generator.py +++ b/gemd/entity/object/has_template_check_generator.py @@ -8,6 +8,8 @@ from inspect import getmodule, getmembers, isclass, signature from typing import Union, Callable, TypeVar +__all__ = ["HasTemplateCheckGenerator"] + T = TypeVar('T') @@ -30,9 +32,9 @@ def _generate_template_check(self, with `self` (provided that object template is defined, attribute templates are defined, etc.). The returned function is intended to work as a `trigger` for a - :py:class `~gemd.entity.valid_list.ValidList`. + :class:`~gemd.entity.valid_list.ValidList`. The behavior following this check -- ignore, warn or raise exception -- is controlled - by the :py:class `~gemd.entity.bounds_validation.WarningLevel` as returned by the + by the :class:`~gemd.entity.bounds_validation.WarningLevel` as returned by the :py:func `~gemd.entity.bounds_validation.get_validation_level`. Parameters diff --git a/gemd/entity/object/ingredient_run.py b/gemd/entity/object/ingredient_run.py index ad53ffc9..4be4a690 100644 --- a/gemd/entity/object/ingredient_run.py +++ b/gemd/entity/object/ingredient_run.py @@ -14,6 +14,8 @@ from typing import Optional, Union, Iterable, List, Mapping, Type, Any +__all__ = ["IngredientRun"] + class IngredientRun(BaseObject, HasQuantities, HasSpec, HasMaterial, HasProcess, @@ -35,25 +37,21 @@ class IngredientRun(BaseObject, for filtering and discoverability. notes: str, optional Long-form notes about the ingredient run. - material: :class:`MaterialRun ` + material: ~gemd.entity.object.material_run.MaterialRun Material that this ingredient is. - process: :class:`ProcessRun ` + process: ~gemd.entity.object.process_run.ProcessRun Process that this ingredient is used in. - mass_fraction: :py:class:`ContinuousValue \ - `, optional + mass_fraction: ~gemd.entity.value.continuous_value.ContinuousValue, optional The mass fraction of the ingredient in the process. - volume_fraction: :py:class:`ContinuousValue \ - `, optional + volume_fraction: ~gemd.entity.value.continuous_value.ContinuousValue, optional The volume fraction of the ingredient in the process. - number_fraction: :py:class:`ContinuousValue \ - `, optional + number_fraction: ~gemd.entity.value.continuous_value.ContinuousValue, optional The number fraction of the ingredient in the process. - absolute_quantity: :py:class:`ContinuousValue \ - `, optional + absolute_quantity: ~gemd.entity.value.continuous_value.ContinuousValue, optional The absolute quantity of the ingredient in the process. - spec: IngredientSpec + spec: ~gemd.entity.object.ingredient_spec.IngredientSpec The specification of which this ingredient is a realization. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. """ diff --git a/gemd/entity/object/ingredient_spec.py b/gemd/entity/object/ingredient_spec.py index 614b6370..7a2f8d41 100644 --- a/gemd/entity/object/ingredient_spec.py +++ b/gemd/entity/object/ingredient_spec.py @@ -12,6 +12,8 @@ from typing import Optional, Union, Iterable, List, Mapping, Type +__all__ = ["IngredientSpec"] + class IngredientSpec(BaseObject, HasQuantities, HasTemplate, HasMaterial, HasProcess, @@ -35,25 +37,21 @@ class IngredientSpec(BaseObject, for filtering and discoverability. notes: str, optional Long-form notes about the ingredient spec. - material: :class:`MaterialSpec ` + material: ~gemd.entity.object.material_spec.MaterialSpec Material that this ingredient is. - process: :class:`ProcessSpec ` + process: ~gemd.entity.object.process_spec.ProcessSpec Process that this ingredient is used in. - mass_fraction: :py:class:`ContinuousValue \ - `, optional + mass_fraction: ~gemd.entity.value.continuous_value.ContinuousValue, optional The mass fraction of the ingredient in the process. - volume_fraction: :class:`ContinuousValue \ - `, optional + volume_fraction: ~gemd.entity.value.continuous_value.ContinuousValue, optional The volume fraction of the ingredient in the process. - number_fraction: :class:`ContinuousValue \ - `, optional + number_fraction: ~gemd.entity.value.continuous_value.ContinuousValue, optional The number fraction of the ingredient in the process. - absolute_quantity: :class:`ContinuousValue \ - `, optional + absolute_quantity: ~gemd.entity.value.continuous_value.ContinuousValue, optional The absolute quantity of the ingredient in the process. labels: List[str], optional Additional labels on the ingredient that must be unique. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. """ diff --git a/gemd/entity/object/material_run.py b/gemd/entity/object/material_run.py index 5d4a5348..a99fd703 100644 --- a/gemd/entity/object/material_run.py +++ b/gemd/entity/object/material_run.py @@ -8,7 +8,10 @@ from gemd.entity.link_by_uid import LinkByUID from gemd.entity.setters import validate_list -from typing import Optional, Union, Iterable, List, Mapping, Type, Any +from typing import TypeVar, Optional, Union, Iterable, List, Mapping, Type, Any + +__all__ = ["MaterialRun"] +MeasurementRunType = TypeVar("MeasurementRunType", bound="MeasurementRun") # noqa: F821 class MaterialRun(BaseObject, HasSpec, HasProcess, typ="material_run", skip={"_measurements"}): @@ -31,23 +34,16 @@ class MaterialRun(BaseObject, HasSpec, HasProcess, typ="material_run", skip={"_m for filtering and discoverability. notes: str, optional Long-form notes about the material run. - process: :class:`ProcessRun ` + process: ~gemd.entity.object.process_run.ProcessRun Process that produces this material. sample_type: str, optional The form of this sample. Optionals are "experimental", "virtual", "production", or "unknown." Default is "unknown." - spec: :class:`MaterialSpec ` + spec: :class:`~gemd.entity.object.material_spec.MaterialSpec` The material specification of which this is an instance. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. - Attributes - ---------- - measurements: List[:class:`MeasurementRun\ - `], optional - Measurements performed on this material. The link is established by creating the - measurement run and settings its `material` field to this material run. - """ def __init__(self, @@ -91,8 +87,13 @@ def process(self, process: Union[ProcessRun, LinkByUID]): raise TypeError("process must be a ProcessRun or LinkByUID: {}".format(process)) @property - def measurements(self) -> List["MeasurementRun"]: # noqa: F821 - """Get a read-only list of the measurement runs.""" + def measurements(self) -> List[MeasurementRunType]: + """Measurements performed on this material. + + The link is established by creating the measurement run and settings its + `material` field to this material run. + + """ return self._measurements @property diff --git a/gemd/entity/object/material_spec.py b/gemd/entity/object/material_spec.py index c676a7a0..3410028e 100644 --- a/gemd/entity/object/material_spec.py +++ b/gemd/entity/object/material_spec.py @@ -13,6 +13,8 @@ from typing import Optional, Union, Iterable, List, Set, Mapping, Type +__all__ = ["MaterialSpec"] + class MaterialSpec(BaseObject, HasTemplate, HasProcess, HasProperties, typ="material_spec"): """ @@ -34,16 +36,15 @@ class MaterialSpec(BaseObject, HasTemplate, HasProcess, HasProperties, typ="mate for filtering and discoverability. notes: str, optional Long-form notes about the material spec. - process: :class:`ProcessSpec ` + process: ~gemd.entity.object.process_spec.ProcessSpec Process that produces this material. - properties: List[:class:`PropertyAndConditions\ - `], optional + properties: List[~gemd.entity.attribute.property_and_conditions.PropertyAndConditions], \ + optional Properties of the material, along with an optional list of conditions under which those properties are measured. - template: :class:`MaterialTemplate\ - `, optional + template: ~gemd.entity.template.material_template.MaterialTemplate, optional A template bounding the valid values for this material's properties. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. """ diff --git a/gemd/entity/object/measurement_run.py b/gemd/entity/object/measurement_run.py index cb10ee8a..60e42302 100644 --- a/gemd/entity/object/measurement_run.py +++ b/gemd/entity/object/measurement_run.py @@ -16,6 +16,8 @@ from typing import Optional, Union, Iterable, Mapping, Type +__all__ = ["MeasurementRun"] + class MeasurementRun(BaseObject, HasMaterial, HasSpec, HasConditions, HasProperties, HasParameters, HasSource, typ="measurement_run"): @@ -39,22 +41,21 @@ class MeasurementRun(BaseObject, HasMaterial, HasSpec, HasConditions, HasPropert for filtering and discoverability. notes: str, optional Long-form notes about the measurement run. - conditions: List[:class:`Condition `], optional + conditions: List[~gemd.entity.attribute.condition.Condition], optional Conditions under which this measurement run occurs. - parameters: List[:class:`Parameter `], optional + parameters: List[~gemd.entity.attribute.parameter.Parameter], optional Parameters of this measurement run. - properties: List[:class:`Property `], optional + properties: List[~gemd.entity.attribute.property.Property], optional Properties that are measured during this measurement run. - spec: :class:`MeasurementSpec ` + spec: ~gemd.entity.object.measurement_spec.MeasurementSpec` The measurement specification of which this is an instance. - material: :class:`MaterialRun ` + material: ~gemd.entity.object.material_run.MaterialRun` The material run being measured. - spec: :class:`MaterialSpec ` + spec: ~gemd.entity.object.material_spec.MaterialSpec` The material specification of which this is an instance. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. - source: :class:`PerformedSource\ - `, optional + source: ~gemd.entity.source.performed_source.PerformedSource, optional Information about the person who performed the run and when. """ diff --git a/gemd/entity/object/measurement_spec.py b/gemd/entity/object/measurement_spec.py index d8637e22..6997002d 100644 --- a/gemd/entity/object/measurement_spec.py +++ b/gemd/entity/object/measurement_spec.py @@ -10,6 +10,8 @@ from typing import Optional, Union, Iterable, Mapping, Type +__all__ = ["MeasurementSpec"] + class MeasurementSpec(BaseObject, HasTemplate, HasParameters, HasConditions, @@ -34,15 +36,14 @@ class MeasurementSpec(BaseObject, for filtering and discoverability. notes: str, optional Long-form notes about the measurement spec. - conditions: List[:class:`Condition `], optional + conditions: List[~gemd.entity.attribute.condition.Condition], optional Conditions under which this measurement spec occurs. - parameters: List[:class:`Parameter `], optional + parameters: List[~gemd.entity.attribute.parameter.Parameter], optional Parameters of this measurement spec. - template: :class:`MeasurementTemplate\ - ` + template: ~gemd.entity.object.measurement_template.MeasurementTemplate A template bounding the valid values for the measurement's properties, parameters, and conditions. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. """ diff --git a/gemd/entity/object/process_run.py b/gemd/entity/object/process_run.py index eb72cfca..f1c73289 100644 --- a/gemd/entity/object/process_run.py +++ b/gemd/entity/object/process_run.py @@ -11,7 +11,11 @@ from gemd.entity.link_by_uid import LinkByUID from gemd.entity.setters import validate_list -from typing import Optional, Union, Iterable, List, Mapping, Dict, Type, Any +from typing import TypeVar, Optional, Union, Iterable, List, Mapping, Dict, Type, Any + +__all__ = ["ProcessRun"] +MaterialRunType = TypeVar("MaterialRunType", bound="MaterialRun") # noqa: F821 +IngredientRunType = TypeVar("IngredientRunType", bound="IngredientRun") # noqa: F821 class ProcessRun(BaseObject, @@ -38,28 +42,17 @@ class ProcessRun(BaseObject, for filtering and discoverability. notes: str, optional Long-form notes about the process run. - conditions: List[:class:`Condition `], optional + conditions: List[~gemd.entity.attribute.condition.Condition], optional Conditions under which this process run occurs. - parameters: List[:class:`Parameter `], optional + parameters: List[~gemd.entity.attribute.parameter.Parameter], optional Parameters of this process run. - spec: :class:`ProcessSpec ` + spec: ~gemd.entity.object.process_spec.ProcessSpec Spec for this process run. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. - source: :class:`PerformedSource\ - `, optional + source: ~gemd.entity.source.performed_source.PerformedSource, optional Information about the person who performed the run and when. - Attributes - ---------- - output_material: :class:`MaterialRun ` - The material run that this process run produces. The link is established by creating - the material run and settings its `process` field to this process run. - - ingredients: List[:class:`IngredientRun `] - Ingredient runs that act as inputs to this process run. The link is established by - creating each ingredient run and setting its `process` field to this process run. - """ def __init__(self, @@ -86,13 +79,23 @@ def __init__(self, self._output_material = None @property - def output_material(self) -> Optional["MaterialRun"]: # noqa: F821 - """Get the output material run.""" + def output_material(self) -> Optional[MaterialRunType]: + """The material run that this process run produces. + + The link is established by creating the material run and settings its + `process` field to this process run. + + """ return self._output_material @property - def ingredients(self) -> List["IngredientRun"]: # noqa: F821 - """Get the input ingredient runs.""" + def ingredients(self) -> List[IngredientRunType]: + """Ingredient runs that act as inputs to this process run. + + The link is established by creating each ingredient run and setting its + `process` field to this process run. + + """ return self._ingredients @staticmethod diff --git a/gemd/entity/object/process_spec.py b/gemd/entity/object/process_spec.py index ac5039ac..40bcb185 100644 --- a/gemd/entity/object/process_spec.py +++ b/gemd/entity/object/process_spec.py @@ -9,7 +9,11 @@ from gemd.entity.link_by_uid import LinkByUID from gemd.entity.setters import validate_list -from typing import Optional, Union, Iterable, List, Mapping, Dict, Type, Any +from typing import TypeVar, Optional, Union, Iterable, List, Mapping, Dict, Type, Any + +__all__ = ["ProcessSpec"] +IngredientSpecType = TypeVar("IngredientSpecType", bound="IngredientSpec") # noqa: F821 +MaterialSpecType = TypeVar("MaterialSpecType", bound="MaterialSpec") # noqa: F821 class ProcessSpec(BaseObject, @@ -36,27 +40,15 @@ class ProcessSpec(BaseObject, for filtering and discoverability. notes: str, optional Long-form notes about the process spec. - conditions: List[:class:`Condition `], optional + conditions: List[~gemd.entity.attribute.condition.Condition], optional Conditions under which this process spec occurs. - parameters: List[:class:`Parameter `], optional + parameters: List[~gemd.entity.attribute.parameter.Parameter], optional Parameters of this process spec. - template: :class:`ProcessTemplate\ - `, optional + template: ~gemd.entity.template.process_template.ProcessTemplate, optional A template bounding the valid values for this process's parameters and conditions. - file_links: List[:class:`FileLink `], optional + file_links: List[~gemd.entity.file_link.FileLink], optional Links to associated files, with resource paths into the files API. - Attributes - ---------- - output_material: :class:`MaterialSpec ` - The material spec that this process spec produces. The link is established by creating - the material spec and settings its `process` field to this process spec. - - ingredients: List[:class:`IngredientSpec\ - `], optional - Ingredient specs that act as inputs to this process spec. The link is established by - creating each ingredient spec and setting its `process` field to this process spec. - """ def __init__(self, @@ -90,13 +82,23 @@ def _template_type() -> Type: return ProcessTemplate @property - def ingredients(self) -> List["IngredientSpec"]: # noqa: F821 - """Get the list of input ingredient specs.""" + def ingredients(self) -> List[IngredientSpecType]: + """Ingredient specs that act as inputs to this process spec. + + The link is established by creating each ingredient spec and setting its + `process` field to this process spec. + + """ return self._ingredients @property - def output_material(self) -> Optional["MaterialSpec"]: # noqa: F821 - """Get the output material spec.""" + def output_material(self) -> Optional[MaterialSpecType]: + """The material spec that this process spec produces. + + The link is established by creating the material spec and settings its + `process` field to this process spec. + + """ return self._output_material def _dict_for_compare(self) -> Dict[str, Any]: diff --git a/gemd/entity/setters.py b/gemd/entity/setters.py index dbbff2b3..6a86e64d 100644 --- a/gemd/entity/setters.py +++ b/gemd/entity/setters.py @@ -3,6 +3,8 @@ from typing import Union, Iterable, Optional, Callable, Type, TypeVar +__all__ = ["validate_list", "validate_str"] + T = TypeVar('T') diff --git a/gemd/entity/source/performed_source.py b/gemd/entity/source/performed_source.py index a2834f2d..3a9823e8 100644 --- a/gemd/entity/source/performed_source.py +++ b/gemd/entity/source/performed_source.py @@ -1,5 +1,7 @@ from gemd.entity.dict_serializable import DictSerializable +__all__ = ["PerformedSource"] + class PerformedSource(DictSerializable, typ="performed_source"): """ diff --git a/gemd/entity/template/attribute_template.py b/gemd/entity/template/attribute_template.py index 6af0f5ae..c74ccd43 100644 --- a/gemd/entity/template/attribute_template.py +++ b/gemd/entity/template/attribute_template.py @@ -2,6 +2,8 @@ from gemd.entity.base_entity import BaseEntity from gemd.entity.bounds.base_bounds import BaseBounds +__all__ = ["AttributeTemplate"] + class AttributeTemplate(BaseEntity): """ @@ -11,7 +13,7 @@ class AttributeTemplate(BaseEntity): ---------- name: str, required The name of the attribute template. - bounds: :py:class:`BaseBounds ` + bounds: ~gemd.entity.bounds.base_bounds.BaseBounds Bounds circumscribe the values that are valid according to this attribute template. description: str, optional A long-form description of the attribute template. @@ -39,15 +41,16 @@ def __init__(self, name, *, description=None, bounds=None, uids=None, tags=None) @property def bounds(self): - """Get the bounds.""" + """Bounds circumscribe the values that are valid according to this attribute template.""" return self._bounds @bounds.setter def bounds(self, bounds): + """Set the bounds.""" if bounds is None: - raise ValueError("Bounds are required on AttributeTemplate") + raise ValueError(f"Bounds are required on {type(self).__name__}s") if not isinstance(bounds, BaseBounds): - raise TypeError("Bounds must be an instance of BaseBounds: {}".format(bounds)) + raise TypeError(f"Bounds must be an instance of BaseBounds: {bounds}") self._bounds = bounds def all_dependencies(self): diff --git a/gemd/entity/template/base_template.py b/gemd/entity/template/base_template.py index 9161ac71..7620e43e 100644 --- a/gemd/entity/template/base_template.py +++ b/gemd/entity/template/base_template.py @@ -6,6 +6,8 @@ from typing import Union, Iterable, Mapping +__all__ = ["BaseTemplate"] + class BaseTemplate(BaseEntity): """ diff --git a/gemd/entity/template/condition_template.py b/gemd/entity/template/condition_template.py index 7a03963c..0a6cfac8 100644 --- a/gemd/entity/template/condition_template.py +++ b/gemd/entity/template/condition_template.py @@ -1,5 +1,7 @@ from gemd.entity.template.attribute_template import AttributeTemplate +__all__ = ["ConditionTemplate"] + class ConditionTemplate(AttributeTemplate, typ="condition_template"): """A template for a condition attribute. @@ -8,7 +10,7 @@ class ConditionTemplate(AttributeTemplate, typ="condition_template"): ---------- name: str, required The name of the condition template. - bounds: :py:class:`BaseBounds ` + bounds: ~gemd.entity.bounds.base_bounds.BaseBounds Bounds circumscribe the values that are valid according to this condition template. description: str, optional A long-form description of the attribute template. diff --git a/gemd/entity/template/has_condition_templates.py b/gemd/entity/template/has_condition_templates.py index 927b6795..6714b10e 100644 --- a/gemd/entity/template/has_condition_templates.py +++ b/gemd/entity/template/has_condition_templates.py @@ -6,7 +6,11 @@ from gemd.entity.template.condition_template import ConditionTemplate from gemd.entity.bounds.base_bounds import BaseBounds -from typing import Optional, Union, Iterable, List, Tuple, Set +from typing import TypeVar, Optional, Union, Iterable, List, Tuple, Set + +__all__ = ["HasConditionTemplates"] +BaseEntityType = TypeVar("BaseEntityType", bound="BaseEntity") # noqa: F821 +ConditionType = TypeVar("ConditionType", bound="Condition") # noqa: F821 class HasConditionTemplates(HasDependencies): @@ -15,7 +19,7 @@ class HasConditionTemplates(HasDependencies): Parameters ---------- - conditions: List[(ConditionTemplate, BaseBounds)] + conditions: List[(~gemd.entity.template.condition_template.ConditionTemplate, BaseBounds)] A list of tuples containing this entity's condition templates as well as any restrictions on those templates' bounds. @@ -34,7 +38,7 @@ def conditions(self) -> List[Union[ConditionTemplate, LinkByUID]]: Returns ------- - List[(ConditionTemplate, bounds)] + List[(~gemd.entity.template.condition_template.ConditionTemplate, BaseBounds)] List of this entity's condition template/bounds pairs """ @@ -49,13 +53,13 @@ def conditions(self, conditions: Iterable[Union[Union[ConditionTemplate, LinkByU Parameters ---------- - conditions: List[(ConditionTemplate, bounds)] + conditions: List[(~gemd.entity.template.condition_template.ConditionTemplate, BaseBounds)] A list of tuples containing this entity's condition templates as well as any restrictions on those templates' bounds. Returns ------- - List[(ConditionTemplate, bounds)] + List[(~gemd.entity.template.condition_template.ConditionTemplate, BaseBounds)] List of this entity's condition template/bounds pairs """ @@ -67,7 +71,7 @@ def conditions(self, conditions: Iterable[Union[Union[ConditionTemplate, LinkByU trigger=BaseTemplate._homogenize_ranges ) - def validate_condition(self, condition: "Condition") -> bool: # noqa: F821 + def validate_condition(self, condition: ConditionType) -> bool: """Check if the condition is consistent w/ this template.""" if condition.template is not None: attr, bnd = next((x for x in self.conditions if condition.template == x[0]), @@ -83,6 +87,6 @@ def validate_condition(self, condition: "Condition") -> bool: # noqa: F821 else: return True # Nothing to check against - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntityType, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {attr[0] for attr in self.conditions} diff --git a/gemd/entity/template/has_parameter_templates.py b/gemd/entity/template/has_parameter_templates.py index 29288b41..423c3eba 100644 --- a/gemd/entity/template/has_parameter_templates.py +++ b/gemd/entity/template/has_parameter_templates.py @@ -6,7 +6,11 @@ from gemd.entity.template.parameter_template import ParameterTemplate from gemd.entity.bounds.base_bounds import BaseBounds -from typing import Optional, Union, Iterable, List, Tuple, Set +from typing import TypeVar, Optional, Union, Iterable, List, Tuple, Set + +__all__ = ["HasParameterTemplates"] +ParameterType = TypeVar("ParameterType", bound="Parameter") # noqa: F821 +BaseEntityType = TypeVar("BaseEntityType", bound="BaseEntity") # noqa: F821 class HasParameterTemplates(HasDependencies): @@ -15,7 +19,7 @@ class HasParameterTemplates(HasDependencies): Parameters ---------- - parameters: List[(ParameterTemplate, BaseBounds)] + parameters: List[(~gemd.entity.template.parameter_template.ParameterTemplate, BaseBounds)] A list of tuples containing this entity's parameter templates as well as any restrictions on those templates' bounds. @@ -34,7 +38,7 @@ def parameters(self) -> List[Union[ParameterTemplate, LinkByUID]]: Returns ------- - List[(ParameterTemplate, bounds)] + List[(~gemd.entity.template.parameter_template.ParameterTemplate, BaseBounds)] List of this entity's parameter template/bounds pairs """ @@ -49,13 +53,13 @@ def parameters(self, parameters: Iterable[Union[Union[ParameterTemplate, LinkByU Parameters ---------- - parameters: List[(ParameterTemplate, bounds)] + parameters: List[(~gemd.entity.template.parameter_template.ParameterTemplate, BaseBounds)] A list of tuples containing this entity's parameter templates as well as any restrictions on those templates' bounds. Returns ------- - List[(ParameterTemplate, bounds)] + List[(~gemd.entity.template.parameter_template.ParameterTemplate, BaseBounds)] List of this entity's parameter template/bounds pairs """ @@ -67,7 +71,7 @@ def parameters(self, parameters: Iterable[Union[Union[ParameterTemplate, LinkByU trigger=BaseTemplate._homogenize_ranges ) - def validate_parameter(self, parameter: "Parameter") -> bool: # noqa: F821 + def validate_parameter(self, parameter: ParameterType) -> bool: """Check if the parameter is consistent w/ this template.""" if parameter.template is not None: attr, bnd = next((x for x in self.parameters if parameter.template == x[0]), @@ -83,6 +87,6 @@ def validate_parameter(self, parameter: "Parameter") -> bool: # noqa: F821 else: return True # Nothing to check against - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntityType, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {attr[0] for attr in self.parameters} diff --git a/gemd/entity/template/has_property_templates.py b/gemd/entity/template/has_property_templates.py index 5cb6810e..0495fd2a 100644 --- a/gemd/entity/template/has_property_templates.py +++ b/gemd/entity/template/has_property_templates.py @@ -6,7 +6,13 @@ from gemd.entity.template.property_template import PropertyTemplate from gemd.entity.bounds.base_bounds import BaseBounds -from typing import Optional, Union, Iterable, List, Set, Tuple +from typing import TypeVar, Optional, Union, Iterable, List, Set, Tuple + +__all__ = ["HasPropertyTemplates"] +BaseEntityType = TypeVar("BaseEntityType", bound="BaseEntity") # noqa: F821 +PropertyType = TypeVar("PropertyType", bound="Property") # noqa: F821 +PropertyAndConditionsType = TypeVar("PropertyAndConditionsType", + bound="PropertyAndConditions") # noqa: F821 class HasPropertyTemplates(HasDependencies): @@ -15,7 +21,7 @@ class HasPropertyTemplates(HasDependencies): Parameters ---------- - properties: List[(PropertyTemplate, BaseBounds)] + properties: List[(~gemd.entity.template.property_template.PropertyTemplate, BaseBounds)] A list of tuples containing this entity's property templates as well as any restrictions on those templates' bounds. @@ -35,7 +41,7 @@ def properties(self) -> List[Tuple[Union[PropertyTemplate, LinkByUID], Returns ------- - List[(PropertyTemplate, bounds)] + List[(~gemd.entity.template.property_template.PropertyTemplate, BaseBounds)] List of this entity's property template/bounds pairs """ @@ -46,11 +52,11 @@ def properties(self, properties: Iterable[Union[Union[PropertyTemplate, LinkByUI Tuple[Union[PropertyTemplate, LinkByUID], Optional[BaseBounds]]]]): """ - Set the list of parameter templates. + Set the list of property templates. Parameters ---------- - properties: List[(PropertyTemplate, bounds)] + properties: List[(~gemd.entity.template.property_template.PropertyTemplate, BaseBounds)] A list of tuples containing this entity's property templates as well as any restrictions on those templates' bounds. @@ -63,9 +69,7 @@ def properties(self, properties: Iterable[Union[Union[PropertyTemplate, LinkByUI trigger=BaseTemplate._homogenize_ranges ) - def validate_property(self, - prop: Union["Property", "PropertyAndConditions"] # noqa: F821 - ) -> bool: # noqa: F821 + def validate_property(self, prop: Union[PropertyType, PropertyAndConditionsType]) -> bool: """Check if the property is consistent w/ this template.""" from gemd.entity.attribute import PropertyAndConditions if isinstance(prop, PropertyAndConditions): @@ -85,6 +89,6 @@ def validate_property(self, else: return True # Nothing to check against - def _local_dependencies(self) -> Set[Union["BaseEntity", "LinkByUID"]]: # noqa: F821 + def _local_dependencies(self) -> Set[Union[BaseEntityType, LinkByUID]]: """Return a set of all immediate dependencies (no recursion).""" return {attr[0] for attr in self.properties} diff --git a/gemd/entity/template/material_template.py b/gemd/entity/template/material_template.py index b2ceb078..bf5e140a 100644 --- a/gemd/entity/template/material_template.py +++ b/gemd/entity/template/material_template.py @@ -2,6 +2,8 @@ from gemd.entity.template.base_template import BaseTemplate from gemd.entity.template.has_property_templates import HasPropertyTemplates +__all__ = ["MaterialTemplate"] + class MaterialTemplate(BaseTemplate, HasPropertyTemplates, typ="material_template"): """ @@ -25,10 +27,9 @@ class MaterialTemplate(BaseTemplate, HasPropertyTemplates, typ="material_templat `Tags `_ are hierarchical strings that store information about an entity. They can be used for filtering and discoverability. - properties: List[:class:`PropertyTemplate \ - `] or \ - List[:class:`PropertyTemplate `,\ - :py:class:`BaseBounds `], optional + properties: ~gemd.entity.template.property_template.PropertyTemplate or \ + List[~gemd.entity.template.property_template.PropertyTemplate, \ + ~gemd.entity.bounds.base_bounds.BaseBounds], optional Templates for associated properties. Each template can be provided by itself, or as a list with the second entry being a separate, *more restrictive* Bounds object that defines the limits of the value for this property. diff --git a/gemd/entity/template/measurement_template.py b/gemd/entity/template/measurement_template.py index bd8b6838..23104c61 100644 --- a/gemd/entity/template/measurement_template.py +++ b/gemd/entity/template/measurement_template.py @@ -4,6 +4,8 @@ from gemd.entity.template.has_parameter_templates import HasParameterTemplates from gemd.entity.template.has_property_templates import HasPropertyTemplates +__all__ = ["MeasurementTemplate"] + class MeasurementTemplate(BaseTemplate, HasPropertyTemplates, HasConditionTemplates, HasParameterTemplates, @@ -29,24 +31,21 @@ class MeasurementTemplate(BaseTemplate, `Tags `_ are hierarchical strings that store information about an entity. They can be used for filtering and discoverability. - conditions: List[:class:`ConditionTemplate \ - `] or \ - List[:class:`ConditionTemplate `,\ - :py:class:`BaseBounds `], optional + conditions: List[~gemd.entity.template.condition_template.ConditionTemplate] or \ + List[~gemd.entity.template.condition_template.ConditionTemplate,\ + ~gemd.entity.bounds.base_bounds.BaseBounds], optional Templates for associated conditions. Each template can be provided by itself, or as a list with the second entry being a separate, *more restrictive* Bounds object that defines the limits of the value for this condition. - parameters: List[:class:`ParameterTemplate \ - `] or \ - List[:class:`ParameterTemplate `,\ - :py:class:`BaseBounds `], optional + parameters: List[~gemd.entity.template.parameter_template.ParameterTemplate] or \ + List[~gemd.entity.template.parameter_template.ParameterTemplate,\ + ~gemd.entity.bounds.base_bounds.BaseBounds], optional Templates for associated parameters. Each template can be provided by itself, or as a list with the second entry being a separate, *more restrictive* Bounds object that defines the limits of the value for this parameter. - properties: List[:class:`PropertyTemplate \ - `] or \ - List[:class:`PropertyTemplate `,\ - :py:class:`BaseBounds `], optional + properties: List[~gemd.entity.template.property_template.PropertyTemplate] or \ + List[~gemd.entity.template.property_template.PropertyTemplate,\ + ~gemd.entity.bounds.base_bounds.BaseBounds], optional Templates for associated properties. Each template can be provided by itself, or as a list with the second entry being a separate, *more restrictive* Bounds object that defines the limits of the value for this property. diff --git a/gemd/entity/template/parameter_template.py b/gemd/entity/template/parameter_template.py index c8e8c4ce..2b733258 100644 --- a/gemd/entity/template/parameter_template.py +++ b/gemd/entity/template/parameter_template.py @@ -1,14 +1,16 @@ from gemd.entity.template.attribute_template import AttributeTemplate +__all__ = ["ParameterTemplate"] + class ParameterTemplate(AttributeTemplate, typ="parameter_template"): """A template for the parameter attribute. - Parameters + Parameters ---------- name: str, required The name of the parameter template. - bounds: :py:class:`BaseBounds ` + bounds: ~gemd.entity.bounds.base_bounds.BaseBounds Bounds circumscribe the values that are valid according to this parameter template. description: str, optional A long-form description of the attribute template. diff --git a/gemd/entity/template/process_template.py b/gemd/entity/template/process_template.py index 307266f8..7325e6fa 100644 --- a/gemd/entity/template/process_template.py +++ b/gemd/entity/template/process_template.py @@ -4,6 +4,8 @@ from gemd.entity.template.has_condition_templates import HasConditionTemplates from gemd.entity.template.has_parameter_templates import HasParameterTemplates +__all__ = ["ProcessTemplate"] + class ProcessTemplate(BaseTemplate, HasConditionTemplates, HasParameterTemplates, @@ -33,17 +35,15 @@ class ProcessTemplate(BaseTemplate, The set of names that a process' ingredients are allowed to use in their name field. allowed_labels: List[str], optional The set of labels that a process' ingredients are allowed to use in their labels field. - conditions: List[:class:`ConditionTemplate \ - `] or \ - List[:class:`ConditionTemplate `,\ - :py:class:`BaseBounds `], optional + conditions: List[~gemd.entity.template.condition_template.ConditionTemplate] or \ + List[~gemd.entity.template.condition_template.ConditionTemplate,\ + ~gemd.entity.bounds.base_bounds.BaseBounds], optional Templates for associated conditions. Each template can be provided by itself, or as a list with the second entry being a separate, *more restrictive* Bounds object that defines the limits of the value for this condition. - parameters: List[:class:`ParameterTemplate \ - `] or \ - List[:class:`ParameterTemplate `,\ - :py:class:`BaseBounds `], optional + parameters: List[~gemd.entity.template.parameter_template.ParameterTemplate] or \ + List[~gemd.entity.template.parameter_template.ParameterTemplate,\ + ~gemd.entity.bounds.base_bounds.BaseBounds], optional Templates for associated parameters. Each template can be provided by itself, or as a list with the second entry being a separate, *more restrictive* Bounds object that defines the limits of the value for this parameter. diff --git a/gemd/entity/template/property_template.py b/gemd/entity/template/property_template.py index f0608333..eb14a300 100644 --- a/gemd/entity/template/property_template.py +++ b/gemd/entity/template/property_template.py @@ -1,5 +1,7 @@ from gemd.entity.template.attribute_template import AttributeTemplate +__all__ = ["PropertyTemplate"] + class PropertyTemplate(AttributeTemplate, typ="property_template"): """A template for the property attribute. @@ -8,7 +10,7 @@ class PropertyTemplate(AttributeTemplate, typ="property_template"): ---------- name: str, required The name of the property template. - bounds: :py:class:`BaseBounds ` + bounds: ~gemd.entity.bounds.base_bounds.BaseBounds Bounds circumscribe the values that are valid according to this property template. description: str, optional A long-form description of the attribute template. diff --git a/gemd/entity/util.py b/gemd/entity/util.py index 23592495..1cb8585a 100644 --- a/gemd/entity/util.py +++ b/gemd/entity/util.py @@ -3,6 +3,8 @@ from typing import List, Dict, Any +__all__ = ["make_instance", "array_like", "complete_material_history"] + def make_instance(base_spec): """ @@ -104,7 +106,7 @@ def complete_material_history(mat) -> List[Dict[str, Any]]: Parameters --------- - mat: MaterialRun + mat: ~gemd.entity.object.material_run.MaterialRun root material run Returns ------- diff --git a/gemd/entity/valid_list.py b/gemd/entity/valid_list.py index 926b251f..52647823 100644 --- a/gemd/entity/valid_list.py +++ b/gemd/entity/valid_list.py @@ -1,6 +1,8 @@ """A list that can validate its contents.""" from typing import Optional, Union, Iterable, Callable, Type, TypeVar +__all__ = ["ValidList"] + T = TypeVar('T') diff --git a/gemd/entity/value/base_value.py b/gemd/entity/value/base_value.py index 18a0ff6a..b02c25f3 100644 --- a/gemd/entity/value/base_value.py +++ b/gemd/entity/value/base_value.py @@ -4,6 +4,8 @@ from abc import abstractmethod +__all__ = ["BaseValue"] + class BaseValue(DictSerializable): """ @@ -11,7 +13,6 @@ class BaseValue(DictSerializable): "Value" is a generic term for the information contained in an :class:`attribute `. - A value may be one of the following types: `RealValue`, `IntegerValue`, `Categorical`. """ @abstractmethod @@ -22,7 +23,6 @@ def _to_bounds(self) -> BaseBounds: Returns ------- BaseBounds - The minimally consistent - :class:`bounds `. + The minimally consistent :class:`bounds `. """ diff --git a/gemd/entity/value/categorical_value.py b/gemd/entity/value/categorical_value.py index 29d8cf90..ddee8992 100644 --- a/gemd/entity/value/categorical_value.py +++ b/gemd/entity/value/categorical_value.py @@ -4,6 +4,8 @@ from abc import abstractmethod +__all__ = ["CategoricalValue"] + class CategoricalValue(BaseValue): """ @@ -21,6 +23,6 @@ def _to_bounds(self) -> CategoricalBounds: ------- CategoricalBounds The minimally consistent - :class:`bounds `. + :class:`gemd.entity.bounds.categorical_bounds.CategoricalBounds`. """ diff --git a/gemd/entity/value/composition_value.py b/gemd/entity/value/composition_value.py index de63835b..511528ca 100644 --- a/gemd/entity/value/composition_value.py +++ b/gemd/entity/value/composition_value.py @@ -4,6 +4,8 @@ from abc import abstractmethod +__all__ = ["CompositionValue"] + class CompositionValue(BaseValue): """Base class for composition values.""" @@ -17,6 +19,6 @@ def _to_bounds(self) -> CompositionBounds: ------- CompositionBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.composition_bounds.CompositionBounds`. """ diff --git a/gemd/entity/value/continuous_value.py b/gemd/entity/value/continuous_value.py index bc074ee9..9bae50af 100644 --- a/gemd/entity/value/continuous_value.py +++ b/gemd/entity/value/continuous_value.py @@ -5,6 +5,8 @@ from abc import abstractmethod +__all__ = ["ContinuousValue"] + class ContinuousValue(BaseValue): """ @@ -47,7 +49,6 @@ def _to_bounds(self) -> RealBounds: Returns ------- RealBounds - The minimally consistent - :class:`bounds `. + The minimally consistent :class:`~gemd.entity.bounds.real_bounds.RealBounds`. """ diff --git a/gemd/entity/value/discrete_categorical.py b/gemd/entity/value/discrete_categorical.py index b1f5e4f9..6d3c1c1b 100644 --- a/gemd/entity/value/discrete_categorical.py +++ b/gemd/entity/value/discrete_categorical.py @@ -1,8 +1,12 @@ """Discrete distribution across several categories.""" +from typing import Optional, Union, Mapping + from gemd.entity.setters import validate_str from gemd.entity.value.categorical_value import CategoricalValue from gemd.entity.bounds import CategoricalBounds +__all__ = ["DiscreteCategorical"] + class DiscreteCategorical(CategoricalValue, typ="discrete_categorical"): """ @@ -21,17 +25,18 @@ class DiscreteCategorical(CategoricalValue, typ="discrete_categorical"): """ - def __init__(self, probabilities=None): + def __init__(self, probabilities: Union[str, Mapping[str, float]] = None): self._probabilities = None self.probabilities = probabilities @property - def probabilities(self) -> dict: + def probabilities(self) -> Mapping[str, float]: """Get the map from categories to probabilities.""" return self._probabilities @probabilities.setter - def probabilities(self, probabilities: dict): + def probabilities(self, probabilities: Optional[Union[str, Mapping[str, float]]]): + """Set the map from categories to probabilities.""" if probabilities is None: self._probabilities = None elif isinstance(probabilities, str): @@ -51,7 +56,7 @@ def _to_bounds(self) -> CategoricalBounds: ------- BaseBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.categorical_bounds.CategoricalBounds`. """ return CategoricalBounds(categories=set(self.probabilities)) diff --git a/gemd/entity/value/empirical_formula.py b/gemd/entity/value/empirical_formula.py index 4701b511..b52d9cc0 100644 --- a/gemd/entity/value/empirical_formula.py +++ b/gemd/entity/value/empirical_formula.py @@ -2,6 +2,8 @@ from gemd.entity.value.composition_value import CompositionValue from gemd.entity.bounds import CompositionBounds +__all__ = ["EmpiricalFormula"] + _all_elements = { 'Tb', 'Be', 'Sb', 'Re', 'Sr', 'Ac', 'Ho', 'Ir', 'Cr', 'Os', 'S', 'Pt', 'Si', 'C', 'V', 'Bi', @@ -61,7 +63,7 @@ def _to_bounds(self) -> CompositionBounds: ------- BaseBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.categorical_bounds.CategoricalBounds`. """ return CompositionBounds(components=EmpiricalFormula._elements(self.formula)) diff --git a/gemd/entity/value/inchi_value.py b/gemd/entity/value/inchi_value.py index 1e8d0ed6..4e7ba263 100644 --- a/gemd/entity/value/inchi_value.py +++ b/gemd/entity/value/inchi_value.py @@ -2,6 +2,8 @@ from gemd.entity.value.molecular_value import MolecularValue from gemd.entity.bounds import MolecularStructureBounds +__all__ = ["InChI"] + class InChI(MolecularValue, typ="inchi"): """ @@ -47,8 +49,7 @@ def _to_bounds(self) -> MolecularStructureBounds: ------- MolecularStructureBounds The minimally consistent - :class:`bounds - `. + :class:`~gemd.entity.bounds.molecular_structure_bounds.MolecularStructureBounds`. """ return MolecularStructureBounds() diff --git a/gemd/entity/value/integer_value.py b/gemd/entity/value/integer_value.py index edac729a..43283b56 100644 --- a/gemd/entity/value/integer_value.py +++ b/gemd/entity/value/integer_value.py @@ -4,6 +4,8 @@ from abc import abstractmethod +__all__ = ["IntegerValue"] + class IntegerValue(BaseValue): """A base class for values that correspond to a distribution over the integers.""" @@ -17,6 +19,6 @@ def _to_bounds(self) -> IntegerBounds: ------- IntegerBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.integer_bounds.IntegerBounds`. """ diff --git a/gemd/entity/value/molecular_value.py b/gemd/entity/value/molecular_value.py index a3e8d6cd..3318cea7 100644 --- a/gemd/entity/value/molecular_value.py +++ b/gemd/entity/value/molecular_value.py @@ -4,6 +4,8 @@ from abc import abstractmethod +__all__ = ["MolecularValue"] + class MolecularValue(BaseValue): """Base class for molecular structure values.""" @@ -17,7 +19,6 @@ def _to_bounds(self) -> MolecularStructureBounds: ------- MolecularStructureBounds The minimally consistent - :class:`bounds - `. + :class:`~gemd.entity.bounds.molecular_structure_bounds.MolecularStructureBounds`. """ diff --git a/gemd/entity/value/nominal_categorical.py b/gemd/entity/value/nominal_categorical.py index 6c6c9c98..5f738619 100644 --- a/gemd/entity/value/nominal_categorical.py +++ b/gemd/entity/value/nominal_categorical.py @@ -3,6 +3,8 @@ from gemd.entity.value.categorical_value import CategoricalValue from gemd.entity.bounds import CategoricalBounds +__all__ = ["NominalCategorical"] + class NominalCategorical(CategoricalValue, typ="nominal_categorical"): """ @@ -39,7 +41,7 @@ def _to_bounds(self) -> CategoricalBounds: ------- BaseBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.categorical_bounds.CategoricalBounds`. """ return CategoricalBounds(categories={self.category}) diff --git a/gemd/entity/value/nominal_composition.py b/gemd/entity/value/nominal_composition.py index a02233cb..ca3f891a 100644 --- a/gemd/entity/value/nominal_composition.py +++ b/gemd/entity/value/nominal_composition.py @@ -2,6 +2,8 @@ from gemd.entity.value.composition_value import CompositionValue from gemd.entity.bounds import CompositionBounds +__all__ = ["NominalComposition"] + class NominalComposition(CompositionValue, typ="nominal_composition"): """ @@ -50,7 +52,7 @@ def _to_bounds(self) -> CompositionBounds: ------- BaseBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.categorical_bounds.CategoricalBounds`. """ return CompositionBounds(components=set(self.quantities)) diff --git a/gemd/entity/value/nominal_integer.py b/gemd/entity/value/nominal_integer.py index 94f090ea..5be33d5c 100644 --- a/gemd/entity/value/nominal_integer.py +++ b/gemd/entity/value/nominal_integer.py @@ -2,6 +2,8 @@ from gemd.entity.value.integer_value import IntegerValue from gemd.entity.bounds import IntegerBounds +__all__ = ["NominalInteger"] + class NominalInteger(IntegerValue, typ="nominal_integer"): """ @@ -40,7 +42,7 @@ def _to_bounds(self) -> IntegerBounds: ------- IntegerBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.integer_bounds.IntegerBounds`. """ return IntegerBounds(lower_bound=self.nominal, upper_bound=self.nominal) diff --git a/gemd/entity/value/nominal_real.py b/gemd/entity/value/nominal_real.py index 7eeb7608..3a79028d 100644 --- a/gemd/entity/value/nominal_real.py +++ b/gemd/entity/value/nominal_real.py @@ -2,6 +2,8 @@ from gemd.entity.value.continuous_value import ContinuousValue from gemd.entity.bounds import RealBounds +__all__ = ["NominalReal"] + class NominalReal(ContinuousValue, typ="nominal_real"): """ @@ -31,7 +33,7 @@ def _to_bounds(self) -> RealBounds: ------- RealBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.real_bounds.RealBounds`. """ return RealBounds(lower_bound=self.nominal, diff --git a/gemd/entity/value/normal_real.py b/gemd/entity/value/normal_real.py index 57915226..4ce1908d 100644 --- a/gemd/entity/value/normal_real.py +++ b/gemd/entity/value/normal_real.py @@ -2,6 +2,8 @@ from gemd.entity.value.continuous_value import ContinuousValue from gemd.entity.bounds import RealBounds +__all__ = ["NormalReal"] + class NormalReal(ContinuousValue, typ="normal_real"): """ @@ -32,7 +34,7 @@ def _to_bounds(self) -> RealBounds: ------- RealBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.real_bounds.RealBounds`. """ return RealBounds(lower_bound=self.mean, diff --git a/gemd/entity/value/smiles_value.py b/gemd/entity/value/smiles_value.py index e871f77f..cfeb2b53 100644 --- a/gemd/entity/value/smiles_value.py +++ b/gemd/entity/value/smiles_value.py @@ -2,6 +2,8 @@ from gemd.entity.value.molecular_value import MolecularValue from gemd.entity.bounds import MolecularStructureBounds +__all__ = ["Smiles"] + class Smiles(MolecularValue, typ="smiles"): """ @@ -41,8 +43,7 @@ def _to_bounds(self) -> MolecularStructureBounds: ------- MolecularStructureBounds The minimally consistent - :class:`bounds - `. + :class:`~gemd.entity.bounds.molecular_structure_bounds.MolecularStructureBounds`. """ return MolecularStructureBounds() diff --git a/gemd/entity/value/uniform_integer.py b/gemd/entity/value/uniform_integer.py index 4cc47f67..40cdb938 100644 --- a/gemd/entity/value/uniform_integer.py +++ b/gemd/entity/value/uniform_integer.py @@ -2,6 +2,8 @@ from gemd.entity.value.integer_value import IntegerValue from gemd.entity.bounds import IntegerBounds +__all__ = ["UniformInteger"] + class UniformInteger(IntegerValue, typ="uniform_integer"): """ @@ -68,7 +70,7 @@ def _to_bounds(self) -> IntegerBounds: ------- IntegerBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.integer_bounds.IntegerBounds`. """ return IntegerBounds(lower_bound=self.lower_bound, upper_bound=self.upper_bound) diff --git a/gemd/entity/value/uniform_real.py b/gemd/entity/value/uniform_real.py index eca0b004..757c68d0 100644 --- a/gemd/entity/value/uniform_real.py +++ b/gemd/entity/value/uniform_real.py @@ -2,6 +2,8 @@ from gemd.entity.value.continuous_value import ContinuousValue from gemd.entity.bounds import RealBounds +__all__ = ["UniformReal"] + class UniformReal(ContinuousValue, typ="uniform_real"): """ @@ -40,7 +42,7 @@ def _to_bounds(self) -> RealBounds: ------- RealBounds The minimally consistent - :class:`bounds `. + :class:`~gemd.entity.bounds.real_bounds.RealBounds`. """ return RealBounds(lower_bound=self.lower_bound, diff --git a/gemd/enumeration/__init__.py b/gemd/enumeration/__init__.py index 2cfcb00b..77c1167f 100644 --- a/gemd/enumeration/__init__.py +++ b/gemd/enumeration/__init__.py @@ -2,3 +2,4 @@ from .origin import Origin from .sample_type import SampleType +__all__ = ["Origin", "SampleType"] diff --git a/gemd/enumeration/base_enumeration.py b/gemd/enumeration/base_enumeration.py index cb8a3df5..849695e9 100644 --- a/gemd/enumeration/base_enumeration.py +++ b/gemd/enumeration/base_enumeration.py @@ -4,26 +4,25 @@ from typing import Optional, Type, Callable from warnings import warn +__all__ = ["BaseEnumeration"] + class BaseEnumeration(str, Enum): - """ - Enumeration class that can convert between enumerations and associated values. + """Enumeration class that can convert between enumerations and associated values. BaseEnumeration is a powerful support class for string enumerations. It inherits from both str and Enum to enable a class with str capabilities but still a restricted data space. All constructors are case-insensitive on input and a given enumeration can recognize multiple synonyms for input, though only one value will - correspond to the value itsself. For example: + correspond to the value itself. For example: - ``` - Fruits(BaseEnumeration): - APPLE = "Apple" - AVOCADO = "Avocado", "Alligator Pear" - ``` + >>> class Fruits(BaseEnumeration): + ... APPLE = "Apple" + ... AVOCADO = "Avocado", "Alligator Pear" - will recognize "apple", "APPLE" and " aPpLe " as referring to Fruits.APPLE, - and "avocado" and "alligator pear" as referring to Fruits.AVOCADO. However, - since str(Fruits.AVOCADO) is "Avocado", Fruits.AVOCADO != "Alligator Pear". + will recognize ``"apple"``, ``"APPLE"`` and ``" aPpLe "`` as referring to Fruits.APPLE, + and ``"avocado"`` and ``"alligator pear"`` as referring to Fruits.AVOCADO. However, + since str(Fruits.AVOCADO) is ``"Avocado"``, Fruits.AVOCADO != ``"Alligator Pear"``. """ @@ -84,7 +83,7 @@ def get_value(cls, name: str) -> str: @classmethod @deprecated(deprecated_in="1.15.0", removed_in="2.0.0", - details="Use from_str for retreiving the correct Enum object.") + details="Use from_str for retrieving the correct Enum object.") def get_enum(cls, name: str) -> "BaseEnumeration": """ Return the enumeration associated with name. diff --git a/gemd/enumeration/origin.py b/gemd/enumeration/origin.py index d1ff78dd..c6817275 100644 --- a/gemd/enumeration/origin.py +++ b/gemd/enumeration/origin.py @@ -1,6 +1,8 @@ """All possible origins of an attribute.""" from gemd.enumeration.base_enumeration import BaseEnumeration +__all__ = ["Origin"] + class Origin(BaseEnumeration): """Enumeration containing all possible origins for an attribute.""" diff --git a/gemd/enumeration/sample_type.py b/gemd/enumeration/sample_type.py index 32209a8c..b8193f0d 100644 --- a/gemd/enumeration/sample_type.py +++ b/gemd/enumeration/sample_type.py @@ -1,6 +1,8 @@ """All possible types of samples.""" from gemd.enumeration.base_enumeration import BaseEnumeration +__all__ = ["SampleType"] + class SampleType(BaseEnumeration): """Enumeration containing all possible sample types for a MaterialRun.""" diff --git a/gemd/json/__init__.py b/gemd/json/__init__.py index f4f6c729..608536ec 100644 --- a/gemd/json/__init__.py +++ b/gemd/json/__init__.py @@ -10,8 +10,8 @@ These methods should provide drop-in support for serialization and deserialization of gemd-containing data structures by replacing imports of ``json`` with those of ``gemd.json``. -It also provides convenience imports of :class:`~gemd_encoder.GEMDEncoder` -and :class:`~gemd_json.GEMDJson`. +It also provides convenience imports of :class:`~gemd.json.gemd_encoder.GEMDEncoder` +and :class:`~gemd.json.gemd_json.GEMDJson`. These classes can be used by developers to integrate gemd with other tools by extending the JSON support provided here to those tools. """ @@ -19,6 +19,11 @@ from .gemd_encoder import GEMDEncoder # noqa: F401 from .gemd_json import GEMDJson +__all__ = [ + "GEMDEncoder", "GEMDJson", + "loads", "dumps", "load", "dump" +] + __default = GEMDJson() diff --git a/gemd/json/gemd_encoder.py b/gemd/json/gemd_encoder.py index 0d8436b1..906b68b8 100644 --- a/gemd/json/gemd_encoder.py +++ b/gemd/json/gemd_encoder.py @@ -3,6 +3,8 @@ from gemd.entity.dict_serializable import DictSerializable +__all__ = ["GEMDEncoder"] + class GEMDEncoder(JSONEncoder): """Rules for encoding gemd objects as json strings.""" diff --git a/gemd/json/gemd_json.py b/gemd/json/gemd_json.py index f01276dc..5017b2d3 100644 --- a/gemd/json/gemd_json.py +++ b/gemd/json/gemd_json.py @@ -1,5 +1,6 @@ import inspect from deprecation import deprecated +import json as json_builtin from typing import Dict, Any, Type from gemd.entity.dict_serializable import DictSerializable @@ -7,7 +8,8 @@ from gemd.entity.link_by_uid import LinkByUID from gemd.json import GEMDEncoder from gemd.util import flatten, substitute_links, set_uuids -import json as json_builtin + +__all__ = ["GEMDJson"] class GEMDJson(object): diff --git a/gemd/units/__init__.py b/gemd/units/__init__.py index 74a96069..5b8ce3c8 100644 --- a/gemd/units/__init__.py +++ b/gemd/units/__init__.py @@ -2,5 +2,7 @@ from .impl import parse_units, convert_units, get_base_units, change_definitions_file, \ UndefinedUnitError, IncompatibleUnitsError, DefinitionSyntaxError -__all__ = [parse_units, convert_units, get_base_units, change_definitions_file, - UndefinedUnitError, IncompatibleUnitsError, DefinitionSyntaxError] +__all__ = [ + "parse_units", "convert_units", "get_base_units", "change_definitions_file", + "UndefinedUnitError", "IncompatibleUnitsError", "DefinitionSyntaxError" +] diff --git a/gemd/units/impl.py b/gemd/units/impl.py index 6fe24b7e..47f1f534 100644 --- a/gemd/units/impl.py +++ b/gemd/units/impl.py @@ -21,6 +21,11 @@ # Store directories so they don't get auto-cleaned until exit _TEMP_DIRECTORY = TemporaryDirectory() +__all__ = [ + "parse_units", "convert_units", "get_base_units", "change_definitions_file", + "UndefinedUnitError", "IncompatibleUnitsError", "DefinitionSyntaxError" +] + def _deploy_default_files() -> str: """Copy the units & constants file into a temporary directory.""" @@ -264,15 +269,15 @@ def parse_units(units: Union[str, Unit, None], Parameters ---------- - units: Union[str, Unit, None] + units: str, Unit, or None The string or Unit representation of the object we wish to display return_unit: boolean - Whether to return a Unit object, vs. whatever was initially passed + Whether to return a pint Unit object, vs. whatever was initially passed Returns ------- - [Union[str, Unit, None]] - The representation; note that the same type that was passed is returned + str, Unit, or None + The representation; note that `return_unit` controls the return type """ if units is None: @@ -299,13 +304,14 @@ def get_base_units(units: Union[str, Unit]) -> Tuple[Unit, float, float]: Parameters ---------- - units: Union[str, Unit, None] - The string or Unit representation of the object we wish to display + units: str, Unit, or None + The representation of the object we wish to display Returns ------- - Tuple[Unit, Number, float] - The base unit, its + Tuple[Unit, float, float] + A tuple of the base unit, its multiplicative conversion factor, and its + additive offset, in that order. """ if isinstance(units, str): diff --git a/gemd/util/impl.py b/gemd/util/impl.py index 64f64acb..d3ebf1e1 100644 --- a/gemd/util/impl.py +++ b/gemd/util/impl.py @@ -38,7 +38,7 @@ def func(base_obj): def cached_isinstance( obj: object, - class_or_tuple: Union[Type, Tuple[Union[Type, Tuple[Type]]]]) -> bool: + class_or_tuple: Union[Type, Tuple[Type]]) -> bool: """ Emulate isinstance builtin to take advantage of functools caching. @@ -46,7 +46,7 @@ def cached_isinstance( ---------- obj: object - class_or_tuple: Union[Type, Tuple[Union[Type, Tuple[Type]]]] + class_or_tuple: Type or Tuple[Type] A single type, a tuple of types (potentially nested) Returns @@ -66,7 +66,7 @@ def cached_isinstance( @functools.lru_cache(maxsize=1024) def _cached_issubclass( cls: Type, - class_or_tuple: Union[Type, Tuple[Union[Type, Tuple[Type]]]]) -> bool: + class_or_tuple: Union[Type, Tuple[Type]]) -> bool: """ Emulate issubclass builtin to take advantage of functools caching. @@ -74,7 +74,7 @@ def _cached_issubclass( ---------- cls: type The class to evaluate - class_or_tuple: Union[Type, Tuple[Union[Type, Tuple[Type]]]] + class_or_tuple: Type or Tuple[Type] A single type, a tuple of types (potentially nested) Returns @@ -254,7 +254,7 @@ def make_index(obj: Union[Iterable, BaseEntity, DictSerializable]): Parameters ---------- - obj: Union[Iterable, Mapping, BaseEntity, DictSerializable] + obj: BaseEntity or Iterable[BaseEntity] target container (dict, list, ...) from which to create an index of GEMD objects """ @@ -399,23 +399,23 @@ def _flatten(base_obj: BaseEntity): return sorted([substitute_links(x) for x in res], key=lambda x: writable_sort_order(x)) -def recursive_foreach(obj: Union[Iterable, BaseEntity, DictSerializable], +def recursive_foreach(obj: Union[Iterable, DictSerializable], func: Callable[[BaseEntity], None], *, apply_first=False): """ Apply a function recursively to each BaseEntity object. - Only objects of type BaseEntity will have the function applied, but the recursion will walk + Only :class:`BaseEntity` objects will have the function applied, but the recursion will walk through all objects. For example, BaseEntity -> list -> BaseEntity will have func applied to both base entities. Parameters ---------- - obj: Union[Iterable, Mapping, BaseEntity, DictSerializable] + obj: DictSerializable or Iterable[DictSerializable], or Iterable[...] target of the operation func: Callable[[BaseEntity], None] - to apply to each contained BaseEntity + function to apply to :class:`BaseEntity` elements apply_first: bool whether to apply the func before applying it to members (default: false) @@ -455,19 +455,23 @@ def recursive_foreach(obj: Union[Iterable, BaseEntity, DictSerializable], return -def recursive_flatmap(obj: Union[Iterable, BaseEntity, DictSerializable], +def recursive_flatmap(obj: Union[Iterable, DictSerializable], func: Callable[[BaseEntity], Iterable], *, unidirectional=True) -> List: """ Recursively apply and accumulate a list-valued function to BaseEntity members. + Only :class:`BaseEntity` objects will have the function applied, but the recursion will walk + through all objects. For example, BaseEntity -> list -> BaseEntity will have func applied + to both base entities. + Parameters ---------- - obj: Union[Iterable, Mapping, BaseEntity, DictSerializable] + obj: DictSerializable or Iterable[DictSerializable], or Iterable[...] target of the operation - func: Callable[[BaseEntity], Iterable] - function to apply; must be list-valued + func: Callable[[BaseEntity], Iterable[Any]] + function to apply to :class:`BaseEntity` elements; must be list-valued unidirectional: bool only recurse through the writeable direction of bidirectional links diff --git a/scripts/build_docs.sh b/scripts/build_docs.sh old mode 100644 new mode 100755 diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 13683a4a..a44c40b4 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -36,7 +36,7 @@ then python $REPO_DIR/scripts/validate_version_bump.py || fi flake8 $REPO_DIR/gemd || exit 1; -derp $REPO_DIR $REPO_DIR/setup.py || exit 1; +derp $REPO_DIR $REPO_DIR/gemd/__version__.py || exit 1; pytest $QUIET $EXITFIRST --cov=$REPO_DIR/gemd \ --cov-report term-missing:skip-covered \ --cov-config=$REPO_DIR/tox.ini --no-cov-on-fail --cov-fail-under=100 \ diff --git a/scripts/validate_version_bump.py b/scripts/validate_version_bump.py index e6a66ca9..fbf4097a 100755 --- a/scripts/validate_version_bump.py +++ b/scripts/validate_version_bump.py @@ -9,7 +9,7 @@ def main(): repo_dir = popen("git rev-parse --show-toplevel", mode="r").read().rstrip() - version_path = relpath(f'{repo_dir}/setup.py', getcwd()) + version_path = relpath(f'{repo_dir}/gemd/__version__.py', getcwd()) try: with open(version_path, "r") as fh: diff --git a/setup.py b/setup.py index afbb3375..a127cd1c 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,23 @@ from setuptools import setup, find_packages +from os import path +from packaging.version import Version +import re packages = find_packages() -packages.append("") + +this_directory = path.abspath(path.dirname(__file__)) +version_file = path.join(this_directory, 'gemd', '__version__.py') +version_re = r'''^__version__\s*=\s*(['"])([\w\.]+)\1$''' +with open(version_file, 'r') as f: + mo = re.search(version_re, f.read(), re.M) + if mo: + version = Version(mo.group(2)) + else: + raise RuntimeError(f"Unable to find version string in {version_file}") setup(name='gemd', - version='1.18.0', + # Update this in gemd/__version__.py + version=str(version), python_requires='>=3.8', url='http://github.com/CitrineInformatics/gemd-python', description="Python binding for Citrine's GEMD data model", diff --git a/test_requirements.txt b/test_requirements.txt index 8d88ee33..c27fa53b 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -5,6 +5,6 @@ pytest-cov==4.0.0 pandas==1.5.0 toolz==0.12.0 derp==0.1.1 -sphinx==4.3.0 -sphinxcontrib-apidoc==0.3.0 +sphinx==5.0.0 sphinx-rtd-theme==1.0.0 +sphinxcontrib-apidoc==0.3.0