diff --git a/nomad/metainfo/CONCEPT.md b/nomad/metainfo/CONCEPT.md
index a5c02f2001b34dd04e0e00050ddb653de0d57a31..9d1fb4324d5695a4bdd3dfda7db36c345cdb97be 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 05d759d772866055e60ca5be3e223710e13edc0b..9a54c3c36ac07652ba13b80bf5d239907dbd5400 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 009557b621ce5382ebe46a0a17b1b78e6840aa6f..3be207f5678cbee913ab704b4168074a935dd2f9 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 0e0f345a134df9a394017537d7cd1da54990f3e1..3b0a3c4f8485b035f84a9443ae781edc548d09e0 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 608cb01533d27489c0358b34b516e79e6796afc7..9c96ca4b204683414f4cbe1ed646da89bc0517ef 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 1e71d23669eea7eb1849bf7c5301207161b4e36c..50ef0a5b74fe38e426424f2d61b3dfa970ead9b0 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.
@@ -99,7 +99,7 @@ class OptimadeEntry(MSection):
a_elastic=dict(type=InnerDoc))
elements = Quantity(
- type=Enum(chemical_symbols), shape=['1..*'],
+ type=MEnum(chemical_symbols), shape=['1..*'],
links=optimade_links('h.6.2.1'),
a_elastic=dict(type=Keyword),
a_optimade=Optimade(query=True, entry=True),
@@ -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='''