Commit 5054c6c7 authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Merge branch 'menum' into 'v0.7.2'

Menum

See merge request !76
parents f13eb598 fc61a028
Pipeline #67316 failed with stages
in 13 minutes and 55 seconds
...@@ -107,7 +107,7 @@ the instances of a sub section. ...@@ -107,7 +107,7 @@ the instances of a sub section.
A `Quantity` definition is a special and concrete `Property` definition: 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'`.) - `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` - `unit`, a (computed) units, e.g. `units.F * units.m`
- `derived_from`, a list of references to other quantity definitions - `derived_from`, a list of references to other quantity definitions
- `synonym`, a reference to another quantity definition - `synonym`, a reference to another quantity definition
...@@ -187,7 +187,7 @@ class System(MSection): ...@@ -187,7 +187,7 @@ class System(MSection):
atom_labels = Quantity( atom_labels = Quantity(
shape=['n_atoms'], shape=['n_atoms'],
type=Enum(ase.data.chemical_symbols), type=MEnum(ase.data.chemical_symbols),
annotations=[ElasticSearchQuantity('keyword')]) annotations=[ElasticSearchQuantity('keyword')])
""" """
Atom labels are ... Atom labels are ...
......
...@@ -42,7 +42,7 @@ Starting example ...@@ -42,7 +42,7 @@ Starting example
A Defines the number of atoms in the system. 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) atom_positions = Quantity(type=float, shape=['n_atoms', 3], unit=Units.m)
simulation_cell = Quantity(type=float, shape=[3, 3], unit=Units.m) simulation_cell = Quantity(type=float, shape=[3, 3], unit=Units.m)
pbc = Quantity(type=bool, shape=[3]) pbc = Quantity(type=bool, shape=[3])
...@@ -209,7 +209,7 @@ Custom data types ...@@ -209,7 +209,7 @@ Custom data types
.. autoclass:: DataType .. autoclass:: DataType
:members: :members:
.. autoclass:: Enum .. autoclass:: MEnum
.. _metainfo-reflection .. _metainfo-reflection
...@@ -275,6 +275,6 @@ A more complex example ...@@ -275,6 +275,6 @@ A more complex example
""" """
from .metainfo import MSection, MCategory, Definition, Property, Quantity, SubSection, \ 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, \ MetainfoReferenceError, DataType, MData, MDataDict, Reference, MResource, m_package, \
units units
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import numpy as np import numpy as np
from datetime import datetime 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']) m_package = Package(links=['http://metainfo.nomad-coe.eu'])
...@@ -82,7 +82,7 @@ class VaspRun(Run): ...@@ -82,7 +82,7 @@ class VaspRun(Run):
m_def = Section(extends_base_section=True) m_def = Section(extends_base_section=True)
x_vasp_raw_format = Quantity( x_vasp_raw_format = Quantity(
type=Enum(['xml', 'outcar']), type=MEnum(['xml', 'outcar']),
description='The file format of the parsed VASP mainfile.') description='The file format of the parsed VASP mainfile.')
......
...@@ -9,7 +9,7 @@ import nomad_meta_info ...@@ -9,7 +9,7 @@ import nomad_meta_info
from nomad import utils from nomad import utils
from nomad.metainfo import Definition, Package, Category, Section, Quantity, SubSection, \ 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) T = TypeVar('T', bound=Definition)
...@@ -246,7 +246,7 @@ class LegacyMetainfoEnvironment: ...@@ -246,7 +246,7 @@ class LegacyMetainfoEnvironment:
elif isinstance(definition.type, Reference): elif isinstance(definition.type, Reference):
dtype_str = 'r' dtype_str = 'r'
result['referencedSections'] = [definition.type.target_section_def.name] result['referencedSections'] = [definition.type.target_section_def.name]
elif isinstance(definition.type, Enum): elif isinstance(definition.type, MEnum):
dtype_str = 'C' dtype_str = 'C'
elif type(definition.type) == np.dtype: elif type(definition.type) == np.dtype:
dtype_str = definition.type.name[0] dtype_str = definition.type.name[0]
......
...@@ -20,6 +20,7 @@ import inspect ...@@ -20,6 +20,7 @@ import inspect
import re import re
import json import json
import itertools import itertools
import numpy as np import numpy as np
import pint import pint
import pint.unit import pint.unit
...@@ -56,14 +57,26 @@ class MetainfoReferenceError(MetainfoError): ...@@ -56,14 +57,26 @@ class MetainfoReferenceError(MetainfoError):
# Metainfo quantity data types # Metainfo quantity data types
class Enum(list): class MEnum():
""" Allows to define str types with values limited to a pre-set list of possible values. """ """Allows to define str types with values limited to a pre-set list of possible values."""
def __init__(self, *args): def __init__(self, *args, **kwargs):
# Supports one big list in place of args
if len(args) == 1 and isinstance(args[0], list): if len(args) == 1 and isinstance(args[0], list):
super().__init__(args[0]) args = args[0]
else: # If non-named arguments are given, the default is to have them placed
super().__init__(args) # 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(): class MProxy():
...@@ -181,7 +194,7 @@ class _QuantityType(DataType): ...@@ -181,7 +194,7 @@ class _QuantityType(DataType):
- python build-in primitives: int, float, bool, str - python build-in primitives: int, float, bool, str
- numpy dtypes, e.g. f, int32 - numpy dtypes, e.g. f, int32
- a section definition to define references - 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` - a custom datatype, i.e. instance of :class:`DataType`
- Any - Any
""" """
...@@ -190,10 +203,10 @@ class _QuantityType(DataType): ...@@ -190,10 +203,10 @@ class _QuantityType(DataType):
if value in [str, int, float, bool]: if value in [str, int, float, bool]:
return value return value
if isinstance(value, Enum): if isinstance(value, MEnum):
for enum_value in value: for enum_value in value._values:
if not isinstance(enum_value, str): 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 return value
if type(value) == np.dtype: if type(value) == np.dtype:
...@@ -221,7 +234,7 @@ class _QuantityType(DataType): ...@@ -221,7 +234,7 @@ class _QuantityType(DataType):
if value is str or value is int or value is float or value is bool: 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__) 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)) return dict(type_kind='Enum', type_data=list(value))
if type(value) == np.dtype: if type(value) == np.dtype:
...@@ -789,8 +802,8 @@ class MSection(metaclass=MObjectMeta): ...@@ -789,8 +802,8 @@ class MSection(metaclass=MObjectMeta):
'The value %s for quantity %s does not follow %s' % 'The value %s for quantity %s does not follow %s' %
(value, quantity_def, quantity_def.type)) (value, quantity_def, quantity_def.type))
elif isinstance(quantity_def.type, Enum): elif isinstance(quantity_def.type, MEnum):
if value not in quantity_def.type: if value not in quantity_def.type._values:
raise TypeError( raise TypeError(
'The value %s is not an enum value for quantity %s.' % 'The value %s is not an enum value for quantity %s.' %
(value, quantity_def)) (value, quantity_def))
...@@ -1055,7 +1068,7 @@ class MSection(metaclass=MObjectMeta): ...@@ -1055,7 +1068,7 @@ class MSection(metaclass=MObjectMeta):
elif type(quantity.type) == np.dtype: elif type(quantity.type) == np.dtype:
pass pass
elif isinstance(quantity.type, Enum): elif isinstance(quantity.type, MEnum):
pass pass
elif quantity.type == Any: elif quantity.type == Any:
...@@ -1273,7 +1286,7 @@ class MSection(metaclass=MObjectMeta): ...@@ -1273,7 +1286,7 @@ class MSection(metaclass=MObjectMeta):
if type(value) == np.ndarray: if type(value) == np.ndarray:
value_shape = value.shape 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)] value_shape = [len(value)]
else: else:
value_shape = [] value_shape = []
...@@ -1467,7 +1480,7 @@ class Quantity(Property): ...@@ -1467,7 +1480,7 @@ class Quantity(Property):
The `type` can be one of: The `type` can be one of:
- a build-in primitive Python type: ``int``, ``str``, ``bool``, ``float`` - 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 section to define references to other sections as quantity values
- a custom meta-info :class:`DataType`, see :ref:`metainfo-custom-types` - a custom meta-info :class:`DataType`, see :ref:`metainfo-custom-types`
- a numpy `dtype`, e.g. ``np.dtype('float32')`` - a numpy `dtype`, e.g. ``np.dtype('float32')``
......
...@@ -2,7 +2,7 @@ from ase.data import chemical_symbols ...@@ -2,7 +2,7 @@ from ase.data import chemical_symbols
from elasticsearch_dsl import Keyword, Integer, Float, InnerDoc, Nested from elasticsearch_dsl import Keyword, Integer, Float, InnerDoc, Nested
import numpy as np 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): def optimade_links(section: str):
...@@ -42,7 +42,7 @@ class Species(MSection): ...@@ -42,7 +42,7 @@ class Species(MSection):
''') ''')
chemical_symbols = Quantity( 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_optimade=Optimade(entry=True), description='''
A list of strings of all chemical elements composing this species. A list of strings of all chemical elements composing this species.
...@@ -99,7 +99,7 @@ class OptimadeEntry(MSection): ...@@ -99,7 +99,7 @@ class OptimadeEntry(MSection):
a_elastic=dict(type=InnerDoc)) a_elastic=dict(type=InnerDoc))
elements = Quantity( elements = Quantity(
type=Enum(chemical_symbols), shape=['1..*'], type=MEnum(chemical_symbols), shape=['1..*'],
links=optimade_links('h.6.2.1'), links=optimade_links('h.6.2.1'),
a_elastic=dict(type=Keyword), a_elastic=dict(type=Keyword),
a_optimade=Optimade(query=True, entry=True), a_optimade=Optimade(query=True, entry=True),
...@@ -217,7 +217,7 @@ class OptimadeEntry(MSection): ...@@ -217,7 +217,7 @@ class OptimadeEntry(MSection):
# TODO assemblies # TODO assemblies
structure_features = Quantity( 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'), links=optimade_links('h.6.2.15'),
a_elastic=dict(type=Keyword), a_elastic=dict(type=Keyword),
a_optimade=Optimade(query=True, entry=True), description=''' a_optimade=Optimade(query=True, entry=True), description='''
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment