Commit 595bc21e authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Added datetime datatype to metainfo.

parent aae8e41a
from .metainfo import MSection, MCategory, Definition, Property, Quantity, SubSection, \
Section, Category, Package, Enum, m_package, units
Section, Category, Package, Enum, Datetime, m_package, units
""" An example metainfo package. """
import numpy as np
from datetime import datetime
from nomad.metainfo import MSection, MCategory, Section, Quantity, Package, SubSection, Enum, units
from nomad.metainfo import MSection, MCategory, Section, Quantity, Package, SubSection, Enum, Datetime, units
m_package = Package(links=[''])
......@@ -18,6 +19,7 @@ class Parsing(MSection):
parser_version = Quantity(type=str)
nomad_version = Quantity(type=str)
warnings = Quantity(type=str, shape=['0..*'])
parse_time = Quantity(type=Datetime)
class System(MSection):
......@@ -93,6 +95,10 @@ if __name__ == '__main__':
run = Run()
run.code_name = 'VASP'
run.code_version = '1.0.0'
parsing = run.m_create(Parsing)
parsing.parse_time =
run.m_as(VaspRun).x_vasp_raw_format = 'outcar'
# The same as
run.x_vasp_raw_format = 'outcar' # type: ignore
......@@ -117,4 +123,4 @@ if __name__ == '__main__':
run = Run.m_from_dict(serializable)
print(m_package.m_to_dict()) # type: ignore, pylint: disable=undefined-variable
# print(m_package.m_to_json(indent=2)) # type: ignore, pylint: disable=undefined-variable
......@@ -134,7 +134,7 @@ See the reference of classes :class:`Section` and :class:`Quantities` for detail
.. autoclass:: Quantity
# TODO validation
# TODO validation and constraints
from typing import Type, TypeVar, Union, Tuple, Iterable, List, Any, Dict, Set, \
Callable as TypingCallable, cast
......@@ -148,6 +148,9 @@ import itertools
import numpy as np
from pint.unit import _Unit
from pint import UnitRegistry
import aniso8601
from datetime import datetime
import pytz
m_package: 'Package' = None
......@@ -384,13 +387,40 @@ class Reference(DataType):
return MProxy(value)
class __Datetime(DataType):
def __parse(self, datetime_str: str) -> datetime:
return aniso8601.parse_datetime(datetime_str)
except ValueError:
date = aniso8601.parse_date(datetime_str)
return datetime(date.year, date.month,
except Exception:
raise TypeError('Invalid date literal "{0}"'.format(datetime_str))
def set_normalize(self, section: 'MSection', quantity_def: 'Quantity', value: Any) -> Any:
if isinstance(value, str):
value = self.__parse(value)
if not isinstance(value, datetime):
raise TypeError('%s is not a datetime.' % value)
return value
def serialize(self, section: 'MSection', quantity_def: 'Quantity', value: Any) -> Any:
return value.isoformat()
def deserialize(self, section: 'MSection', quantity_def: 'Quantity', value: Any) -> Any:
return self.__parse(value)
Dimension = __Dimension()
Unit = __Unit()
QuantityType = __QuantityType()
Callable = __Callable()
# TODO class Datetime(DataType)
Datetime = __Datetime()
class MObjectMeta(type):
......@@ -737,10 +767,6 @@ class MSection(metaclass=MObjectMeta):
'The value %s is not an enum value for quantity %s.' %
(value, quantity_def))
elif quantity_def in [Quantity.type, Quantity.derived]:
# TODO check these special cases for Quantity quantities
elif quantity_def.type == Any:
......@@ -999,16 +1025,19 @@ class MSection(metaclass=MObjectMeta):
dct.pop('m_parent_index', None)
dct.pop('m_parent_sub_section', None)
def items():
section = cls()
for name, sub_section_def in section_def.all_sub_sections.items():
if name in dct:
sub_section_value = dct.pop(name)
if sub_section_def.repeats:
yield name, [
for sub_section_dct in sub_section_value]
for sub_section_dct in sub_section_value:
sub_section = sub_section_def.sub_section.section_cls.m_from_dict(sub_section_dct)
section.m_add_sub_section(sub_section_def, sub_section)
yield name, sub_section_def.sub_section.section_cls.m_from_dict(sub_section_value)
sub_section = sub_section_def.sub_section.section_cls.m_from_dict(sub_section_value)
section.m_add_sub_section(sub_section_def, sub_section)
for name, quantity_def in section_def.all_quantities.items():
if name in dct:
......@@ -1019,25 +1048,20 @@ class MSection(metaclass=MObjectMeta):
if isinstance(quantity_def.type, DataType):
dimensions = len(quantity_def.shape)
# TODO hand in the context, which is currently create after!
if dimensions == 0:
quantity_value = quantity_def.type.deserialize(
None, quantity_def, quantity_value)
section, quantity_def, quantity_value)
elif dimensions == 1:
quantity_value = list(
quantity_def.type.deserialize(None, quantity_def, item)
quantity_def.type.deserialize(section, quantity_def, item)
for item in quantity_value)
raise MetainfoError(
'Only numpy quantities can have more than 1 dimension.')
yield name, quantity_value
section.m_data.dct[name] = quantity_value # type: ignore
dct = {key: value for key, value in items()}
section_instance = cast(MSectionBound, section_def.section_cls())
# TODO !do not update, but set directly!
return section_instance
return section
def m_to_json(self, **kwargs):
"""Returns the data of this section as a json string. """
......@@ -1271,9 +1295,6 @@ class Quantity(Property):
virtual: 'Quantity' = None
# TODO derived_from = Quantity(type=Quantity, shape=['0..*'])
# TODO categories = Quantity(type=Category, shape=['0..*'])
# TODO converter = Quantity(type=Converter), a class with set of functions for
# normalizing, (de-)serializing values.
def __get__(self, obj, cls):
if obj is None:
Supports Markdown
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