From 62449dfb40db5f37ad1b8be460d3ba8b321afee4 Mon Sep 17 00:00:00 2001 From: Lauri Himanen <lauri.himanen@gmail.com> Date: Fri, 17 Jan 2020 12:30:51 +0200 Subject: [PATCH] Renamed Enum class to MEnum, added possibility to tie the enum values to variables. --- nomad/metainfo/CONCEPT.md | 4 ++-- nomad/metainfo/__init__.py | 6 ++--- nomad/metainfo/example.py | 4 ++-- nomad/metainfo/legacy.py | 4 ++-- nomad/metainfo/metainfo.py | 45 ++++++++++++++++++++++++-------------- nomad/metainfo/optimade.py | 6 ++--- 6 files changed, 41 insertions(+), 28 deletions(-) diff --git a/nomad/metainfo/CONCEPT.md b/nomad/metainfo/CONCEPT.md index a5c02f2001..9d1fb4324d 100644 --- a/nomad/metainfo/CONCEPT.md +++ b/nomad/metainfo/CONCEPT.md @@ -107,7 +107,7 @@ the instances of a sub section. A `Quantity` definition is a special and concrete `Property` definition: - `shape`, a list of either `int`, references to a dimension (quantity definition), or limits definitions (e.g. `'1..n'`, `'0..n'`.) -- `type`, a primitive or Enum type +- `type`, a primitive or MEnum type - `unit`, a (computed) units, e.g. `units.F * units.m` - `derived_from`, a list of references to other quantity definitions - `synonym`, a reference to another quantity definition @@ -187,7 +187,7 @@ class System(MSection): atom_labels = Quantity( shape=['n_atoms'], - type=Enum(ase.data.chemical_symbols), + type=MEnum(ase.data.chemical_symbols), annotations=[ElasticSearchQuantity('keyword')]) """ Atom labels are ... diff --git a/nomad/metainfo/__init__.py b/nomad/metainfo/__init__.py index 05d759d772..9a54c3c36a 100644 --- a/nomad/metainfo/__init__.py +++ b/nomad/metainfo/__init__.py @@ -42,7 +42,7 @@ Starting example A Defines the number of atoms in the system. ''') - atom_labels = Quantity(type=Enum(ase.data.chemical_symbols), shape['n_atoms']) + atom_labels = Quantity(type=MEnum(ase.data.chemical_symbols), shape['n_atoms']) atom_positions = Quantity(type=float, shape=['n_atoms', 3], unit=Units.m) simulation_cell = Quantity(type=float, shape=[3, 3], unit=Units.m) pbc = Quantity(type=bool, shape=[3]) @@ -209,7 +209,7 @@ Custom data types .. autoclass:: DataType :members: -.. autoclass:: Enum +.. autoclass:: MEnum .. _metainfo-reflection @@ -275,6 +275,6 @@ A more complex example """ from .metainfo import MSection, MCategory, Definition, Property, Quantity, SubSection, \ - Section, Category, Package, Environment, Enum, Datetime, MProxy, MetainfoError, DeriveError, \ + Section, Category, Package, Environment, MEnum, Datetime, MProxy, MetainfoError, DeriveError, \ MetainfoReferenceError, DataType, MData, MDataDict, Reference, MResource, m_package, \ units diff --git a/nomad/metainfo/example.py b/nomad/metainfo/example.py index 009557b621..3be207f567 100644 --- a/nomad/metainfo/example.py +++ b/nomad/metainfo/example.py @@ -3,7 +3,7 @@ import numpy as np from datetime import datetime -from nomad.metainfo import MSection, MCategory, Section, Quantity, Package, SubSection, Enum, Datetime, units +from nomad.metainfo import MSection, MCategory, Section, Quantity, Package, SubSection, MEnum, Datetime, units m_package = Package(links=['http://metainfo.nomad-coe.eu']) @@ -82,7 +82,7 @@ class VaspRun(Run): m_def = Section(extends_base_section=True) x_vasp_raw_format = Quantity( - type=Enum(['xml', 'outcar']), + type=MEnum(['xml', 'outcar']), description='The file format of the parsed VASP mainfile.') diff --git a/nomad/metainfo/legacy.py b/nomad/metainfo/legacy.py index 0e0f345a13..3b0a3c4f84 100644 --- a/nomad/metainfo/legacy.py +++ b/nomad/metainfo/legacy.py @@ -9,7 +9,7 @@ import nomad_meta_info from nomad import utils from nomad.metainfo import Definition, Package, Category, Section, Quantity, SubSection, \ - Environment, Enum, Reference, MSection, units + Environment, MEnum, Reference, MSection, units T = TypeVar('T', bound=Definition) @@ -246,7 +246,7 @@ class LegacyMetainfoEnvironment: elif isinstance(definition.type, Reference): dtype_str = 'r' result['referencedSections'] = [definition.type.target_section_def.name] - elif isinstance(definition.type, Enum): + elif isinstance(definition.type, MEnum): dtype_str = 'C' elif type(definition.type) == np.dtype: dtype_str = definition.type.name[0] diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py index 608cb01533..9c96ca4b20 100644 --- a/nomad/metainfo/metainfo.py +++ b/nomad/metainfo/metainfo.py @@ -20,6 +20,7 @@ import inspect import re import json import itertools + import numpy as np import pint import pint.unit @@ -56,14 +57,26 @@ class MetainfoReferenceError(MetainfoError): # Metainfo quantity data types -class Enum(list): - """ Allows to define str types with values limited to a pre-set list of possible values. """ - def __init__(self, *args): +class MEnum(): + """Allows to define str types with values limited to a pre-set list of possible values.""" + def __init__(self, *args, **kwargs): + # Supports one big list in place of args if len(args) == 1 and isinstance(args[0], list): - super().__init__(args[0]) + args = args[0] - else: - super().__init__(args) + # If non-named arguments are given, the default is to have them placed + # into a dictionary with their string value as both the enum name and + # the value. + for arg in args: + if arg in kwargs: + raise ValueError("Duplicate value '{}' provided for enum".format(arg)) + kwargs[arg] = arg + + self._values = set(kwargs.values()) # For allowing constant time member check + self._map = kwargs + + def __getattr__(self, attr): + return self._map[attr] class MProxy(): @@ -181,7 +194,7 @@ class _QuantityType(DataType): - python build-in primitives: int, float, bool, str - numpy dtypes, e.g. f, int32 - a section definition to define references - - an Enum instance to use it's values as possible str values + - an MEnum instance to use it's values as possible str values - a custom datatype, i.e. instance of :class:`DataType` - Any """ @@ -190,10 +203,10 @@ class _QuantityType(DataType): if value in [str, int, float, bool]: return value - if isinstance(value, Enum): - for enum_value in value: + if isinstance(value, MEnum): + for enum_value in value._values: if not isinstance(enum_value, str): - raise TypeError('Enum value %s is not a string.' % enum_value) + raise TypeError('MEnum value %s is not a string.' % enum_value) return value if type(value) == np.dtype: @@ -221,7 +234,7 @@ class _QuantityType(DataType): if value is str or value is int or value is float or value is bool: return dict(type_kind='python', type_data=value.__name__) - if isinstance(value, Enum): + if isinstance(value, MEnum): return dict(type_kind='Enum', type_data=list(value)) if type(value) == np.dtype: @@ -789,8 +802,8 @@ class MSection(metaclass=MObjectMeta): 'The value %s for quantity %s does not follow %s' % (value, quantity_def, quantity_def.type)) - elif isinstance(quantity_def.type, Enum): - if value not in quantity_def.type: + elif isinstance(quantity_def.type, MEnum): + if value not in quantity_def.type._values: raise TypeError( 'The value %s is not an enum value for quantity %s.' % (value, quantity_def)) @@ -1055,7 +1068,7 @@ class MSection(metaclass=MObjectMeta): elif type(quantity.type) == np.dtype: pass - elif isinstance(quantity.type, Enum): + elif isinstance(quantity.type, MEnum): pass elif quantity.type == Any: @@ -1273,7 +1286,7 @@ class MSection(metaclass=MObjectMeta): if type(value) == np.ndarray: value_shape = value.shape - if isinstance(value, list) and not isinstance(value, Enum): + if isinstance(value, list) and not isinstance(value, MEnum): value_shape = [len(value)] else: value_shape = [] @@ -1467,7 +1480,7 @@ class Quantity(Property): The `type` can be one of: - a build-in primitive Python type: ``int``, ``str``, ``bool``, ``float`` - - an instance of :class:`Enum`, e.g. ``Enum('one', 'two', 'three')`` + - an instance of :class:`MEnum`, e.g. ``MEnum('one', 'two', 'three')`` - a section to define references to other sections as quantity values - a custom meta-info :class:`DataType`, see :ref:`metainfo-custom-types` - a numpy `dtype`, e.g. ``np.dtype('float32')`` diff --git a/nomad/metainfo/optimade.py b/nomad/metainfo/optimade.py index 1e71d23669..ef571ef0b9 100644 --- a/nomad/metainfo/optimade.py +++ b/nomad/metainfo/optimade.py @@ -2,7 +2,7 @@ from ase.data import chemical_symbols from elasticsearch_dsl import Keyword, Integer, Float, InnerDoc, Nested import numpy as np -from nomad.metainfo import MSection, Section, Quantity, SubSection, Enum, units +from nomad.metainfo import MSection, Section, Quantity, SubSection, MEnum, units def optimade_links(section: str): @@ -42,7 +42,7 @@ class Species(MSection): ''') chemical_symbols = Quantity( - type=Enum(chemical_symbols + ['x', 'vacancy']), shape=['1..*'], + type=MEnum(chemical_symbols + ['x', 'vacancy']), shape=['1..*'], a_optimade=Optimade(entry=True), description=''' A list of strings of all chemical elements composing this species. @@ -217,7 +217,7 @@ class OptimadeEntry(MSection): # TODO assemblies structure_features = Quantity( - type=Enum(['disorder', 'unknown_positions', 'assemblies']), shape=['1..*'], + type=MEnum(['disorder', 'unknown_positions', 'assemblies']), shape=['1..*'], links=optimade_links('h.6.2.15'), a_elastic=dict(type=Keyword), a_optimade=Optimade(query=True, entry=True), description=''' -- GitLab