# Path: invenio_records/dictutils.py
# def dict_lookup(source, lookup_key, parent=False):
#     """Make a lookup into a dict based on a dot notation.
# 
#     Examples of the supported dot notation:
# 
#     - ``'a'`` - Equivalent to ``source['a']``
#     - ``'a.b'`` - Equivalent to ``source['a']['b']``
#     - ``'a.b.0'`` - Equivalent to ``source['a']['b'][0]`` (for lists)
# 
#     List notation is also supported:
# 
#     - `['a']``
#     - ``['a','b']``
#     - ``['a','b', 0]``
# 
#     :param source: The dictionary object to perform the lookup in.
#     :param parent: If parent argument is True, returns the parent node of
#                    matched object.
#     :param lookup_key: A string using dot notation, or a list of keys.
#     """
#     # Copied from dictdiffer (CERN contributed part) and slightly modified.
#     keys = parse_lookup_key(lookup_key)
# 
#     if parent:
#         keys = keys[:-1]
# 
#     # Lookup the key
#     value = source
#     for key in keys:
#         try:
#             if isinstance(value, list):
#                 key = int(key)
#             value = value[key]
#         except (TypeError, IndexError, ValueError) as exc:
#             raise KeyError(lookup_key) from exc
#     return value
# 
# def parse_lookup_key(lookup_key):
#     """Parse a lookup key."""
#     if not lookup_key:
#         raise KeyError("No lookup key specified")
# 
#     # Parse the list of keys
#     if isinstance(lookup_key, str):
#         keys = lookup_key.split('.')
#     elif isinstance(lookup_key, list):
#         keys = lookup_key
#     else:
#         raise TypeError('lookup must be string or list')
# 
#     return keys
# 
# Path: invenio_records/extensions.py
# class ExtensionMixin:
#     """Defines the methods needed by an extension."""
# 
#     def pre_init(self, record, data, model=None, **kwargs):
#         """Called when a new record instance is initialized.
# 
#         Called when a new record is instantiated (i.e. during all
#         ``Record({...})``). This means it's also called when e.g. a record
#         is created via ``Record.create()``.
# 
#         :param data: The dict passed to the record's constructor.
#         :param model: The model class used for initialization.
#         """
# 
#     def post_init(self, record, data, model=None, **kwargs):
#         """Called after a record is initialized."""
# 
#     def pre_dump(self, record, data, dumper=None):
#         """Called before a record is dumped."""
# 
#     def post_dump(self, record, data, dumper=None):
#         """Called after a record is dumped."""
# 
#     def pre_load(self, data, loader=None):
#         """Called before a record is loaded."""
# 
#     def post_load(self, record, data, loader=None):
#         """Called after a record is loaded."""
# 
#     def pre_create(self, record):
#         """Called before a record is created."""
# 
#     def post_create(self, record):
#         """Called after a record is created."""
# 
#     def pre_commit(self, record):
#         """Called before a record is committed."""
# 
#     def pre_delete(self, record, force=False):
#         """Called before a record is deleted."""
# 
#     def post_delete(self, record, force=False):
#         """Called after a record is deleted."""
# 
#     def pre_revert(self, record, revision):
#         """Called before a record is reverted."""
# 
#     def post_revert(self, new_record, revision):
#         """Called after a record is reverted."""
# 
# class RecordExtension(ExtensionMixin):
#     """Base class for a record extensions."""
# 
# class RecordMeta(type):
#     """Metaclass responsible for initializing the extension registry."""
# 
#     def __new__(mcs, name, bases, attrs):
#         """Create a new record class."""
#         # Initialise an "_extensions" attribute on each class, to ensure each
#         # class have a separate extensions registry.
#         if '_extensions' not in attrs:
#             attrs['_extensions'] = []
# 
#         # Construct the class.
#         return super().__new__(mcs, name, bases, attrs)


import inspect
import warnings
from ..dictutils import dict_lookup, parse_lookup_key
from ..extensions import ExtensionMixin, RecordExtension, RecordMeta
        This ensures that a field has access to the attribute name used on the
        class. In the following example, the attribute name ``schema`` would be
        set in the ``ConstantField`` object instance.

        .. code-block:: python

            class MyRecord(Record, SystemFieldsMixin):
                schema = ConstantField(...)
        """
        self._attr_name = name

    def post_init(self, record, data, model=None, field_data=None):
        """Core implementation of post_init to support argument loading."""
        if field_data is not None:
            self.__set__(record, field_data)

    def get_dictkey(self, instance):
        """Helper to use a lookup key to get a nested object.

        Assume the key have been set in ``self.key``
        """
        try:
            return dict_lookup(instance, self.key)
        except KeyError:
            return None

    def set_dictkey(self, instance, value, create_if_missing=False):
        """Helper to set value using a lookup key on a nested object."""
        keys = parse_lookup_key(self.key)
        try:

# Path: invenio_records/dictutils.py
# def dict_lookup(source, lookup_key, parent=False):
#     """Make a lookup into a dict based on a dot notation.
# 
#     Examples of the supported dot notation:
# 
#     - ``'a'`` - Equivalent to ``source['a']``
#     - ``'a.b'`` - Equivalent to ``source['a']['b']``
#     - ``'a.b.0'`` - Equivalent to ``source['a']['b'][0]`` (for lists)
# 
#     List notation is also supported:
# 
#     - `['a']``
#     - ``['a','b']``
#     - ``['a','b', 0]``
# 
#     :param source: The dictionary object to perform the lookup in.
#     :param parent: If parent argument is True, returns the parent node of
#                    matched object.
#     :param lookup_key: A string using dot notation, or a list of keys.
#     """
#     # Copied from dictdiffer (CERN contributed part) and slightly modified.
#     keys = parse_lookup_key(lookup_key)
# 
#     if parent:
#         keys = keys[:-1]
# 
#     # Lookup the key
#     value = source
#     for key in keys:
#         try:
#             if isinstance(value, list):
#                 key = int(key)
#             value = value[key]
#         except (TypeError, IndexError, ValueError) as exc:
#             raise KeyError(lookup_key) from exc
#     return value
# 
# def parse_lookup_key(lookup_key):
#     """Parse a lookup key."""
#     if not lookup_key:
#         raise KeyError("No lookup key specified")
# 
#     # Parse the list of keys
#     if isinstance(lookup_key, str):
#         keys = lookup_key.split('.')
#     elif isinstance(lookup_key, list):
#         keys = lookup_key
#     else:
#         raise TypeError('lookup must be string or list')
# 
#     return keys
# 
# Path: invenio_records/extensions.py
# class ExtensionMixin:
#     """Defines the methods needed by an extension."""
# 
#     def pre_init(self, record, data, model=None, **kwargs):
#         """Called when a new record instance is initialized.
# 
#         Called when a new record is instantiated (i.e. during all
#         ``Record({...})``). This means it's also called when e.g. a record
#         is created via ``Record.create()``.
# 
#         :param data: The dict passed to the record's constructor.
#         :param model: The model class used for initialization.
#         """
# 
#     def post_init(self, record, data, model=None, **kwargs):
#         """Called after a record is initialized."""
# 
#     def pre_dump(self, record, data, dumper=None):
#         """Called before a record is dumped."""
# 
#     def post_dump(self, record, data, dumper=None):
#         """Called after a record is dumped."""
# 
#     def pre_load(self, data, loader=None):
#         """Called before a record is loaded."""
# 
#     def post_load(self, record, data, loader=None):
#         """Called after a record is loaded."""
# 
#     def pre_create(self, record):
#         """Called before a record is created."""
# 
#     def post_create(self, record):
#         """Called after a record is created."""
# 
#     def pre_commit(self, record):
#         """Called before a record is committed."""
# 
#     def pre_delete(self, record, force=False):
#         """Called before a record is deleted."""
# 
#     def post_delete(self, record, force=False):
#         """Called after a record is deleted."""
# 
#     def pre_revert(self, record, revision):
#         """Called before a record is reverted."""
# 
#     def post_revert(self, new_record, revision):
#         """Called after a record is reverted."""
# 
# class RecordExtension(ExtensionMixin):
#     """Base class for a record extensions."""
# 
# class RecordMeta(type):
#     """Metaclass responsible for initializing the extension registry."""
# 
#     def __new__(mcs, name, bases, attrs):
#         """Create a new record class."""
#         # Initialise an "_extensions" attribute on each class, to ensure each
#         # class have a separate extensions registry.
#         if '_extensions' not in attrs:
#             attrs['_extensions'] = []
# 
#         # Construct the class.
#         return super().__new__(mcs, name, bases, attrs)


# Path: invenio_records/systemfields/base.py
import inspect
import warnings
from ..dictutils import dict_lookup, parse_lookup_key
from ..extensions import ExtensionMixin, RecordExtension, RecordMeta

        This ensures that a field has access to the attribute name used on the
        class. In the following example, the attribute name ``schema`` would be
        set in the ``ConstantField`` object instance.

        .. code-block:: python

            class MyRecord(Record, SystemFieldsMixin):
                schema = ConstantField(...)
        """
        self._attr_name = name

    def post_init(self, record, data, model=None, field_data=None):
        """Core implementation of post_init to support argument loading."""
        if field_data is not None:
            self.__set__(record, field_data)

    def get_dictkey(self, instance):
        """Helper to use a lookup key to get a nested object.

        Assume the key have been set in ``self.key``
        """
        try:
            return dict_lookup(instance, self.key)
        except KeyError:
            return None

    def set_dictkey(self, instance, value, create_if_missing=False):
        """Helper to set value using a lookup key on a nested object."""
        keys = parse_lookup_key(self.key)
        try:

            parent = dict_lookup(instance, keys, parent=True)