# Path: invenio_records/dictutils.py
# def clear_none(d):
#     """Clear None values and empty dicts from a dict."""
#     del_keys = []
#     for k, v in d.items():
#         if v is None:
#             del_keys.append(k)
#         elif isinstance(v, dict):
#             clear_none(v)
#             if v == {}:
#                 del_keys.append(k)
#         elif isinstance(v, list):
#             clear_none_list(v)
#             if v == []:
#                 del_keys.append(k)
# 
#     # Delete the keys (cannot be done during the dict iteration)
#     for k in del_keys:
#         del d[k]
# 
# 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
# 
# Path: invenio_records/dumpers/base.py
# class Dumper:
#     """Interface for dumpers."""
# 
#     def dump(self, record, data):
#         """Dump a record that can be used a source document for Elasticsearch.
# 
#         The job of this method is to create a Python dictionary from the record
#         provided in the argument.
# 
#         If you overwrite this method without calling super, then you should
#         ensure that you make a deep copy of the record dictionary, to avoid
#         that changes to the dump affects the record.
# 
#         :param record: The record to dump.
#         :param data: The initial dump data passed in by ``record.dumps()``.
#         """
#         data.update(deepcopy(dict(record)))
#         return data
# 
#     def load(self, data, record_cls):
#         """Load a record from the source document of an Elasticsearch hit.
# 
#         The job of this method, is to create a record of type ``record_cls``
#         based on the input ``data``.
# 
#         :param data: A Python dictionary representing the data to load.
#         :param records_cls: The record class to be constructed.
#         :returns: A instance of ``record_cls``.
#         """
#         raise NotImplementedError()
# 
# Path: invenio_records/errors.py
# class MissingModelError(RecordsError):
#     """Error raised when a record has no model."""
# 
# Path: invenio_records/models.py
# class RecordMetadata(db.Model, RecordMetadataBase):
#     """Represent a record metadata."""
# 
#     __tablename__ = 'records_metadata'
# 
#     # Enables SQLAlchemy-Continuum versioning
#     __versioned__ = {}
# 
# Path: invenio_records/signals.py



import inspect
import warnings
from copy import deepcopy
from flask import current_app
from invenio_db import db
from jsonpatch import apply_patch
from sqlalchemy.orm.attributes import flag_modified
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy_continuum.utils import parent_class
from werkzeug.local import LocalProxy
from .dictutils import clear_none, dict_lookup
from .dumpers import Dumper
from .errors import MissingModelError
from .models import RecordMetadata
from .signals import after_record_delete, after_record_insert, \
    after_record_revert, after_record_update, before_record_delete, \
    before_record_insert, before_record_revert, before_record_update
            )

        return self

    def delete(self, force=False):
        """Delete a record.

        If `force` is ``False``, the record is soft-deleted: record data will
        be deleted but the record identifier and the history of the record will
        be kept. This ensures that the same record identifier cannot be used
        twice, and that you can still retrieve its history. If `force` is
        ``True``, then the record is completely deleted from the database.

        #. Send a signal :data:`invenio_records.signals.before_record_delete`
           with the current record as parameter.

        #. Delete or soft-delete the current record.

        #. Send a signal :data:`invenio_records.signals.after_record_delete`
           with the current deleted record as parameter.

        :param force: if ``True``, completely deletes the current record from
               the database, otherwise soft-deletes it.
        :returns: The deleted :class:`Record` instance.
        """
        if self.model is None:
            raise MissingModelError()

        with db.session.begin_nested():
            if self.send_signals:

# Path: invenio_records/dictutils.py
# def clear_none(d):
#     """Clear None values and empty dicts from a dict."""
#     del_keys = []
#     for k, v in d.items():
#         if v is None:
#             del_keys.append(k)
#         elif isinstance(v, dict):
#             clear_none(v)
#             if v == {}:
#                 del_keys.append(k)
#         elif isinstance(v, list):
#             clear_none_list(v)
#             if v == []:
#                 del_keys.append(k)
# 
#     # Delete the keys (cannot be done during the dict iteration)
#     for k in del_keys:
#         del d[k]
# 
# 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
# 
# Path: invenio_records/dumpers/base.py
# class Dumper:
#     """Interface for dumpers."""
# 
#     def dump(self, record, data):
#         """Dump a record that can be used a source document for Elasticsearch.
# 
#         The job of this method is to create a Python dictionary from the record
#         provided in the argument.
# 
#         If you overwrite this method without calling super, then you should
#         ensure that you make a deep copy of the record dictionary, to avoid
#         that changes to the dump affects the record.
# 
#         :param record: The record to dump.
#         :param data: The initial dump data passed in by ``record.dumps()``.
#         """
#         data.update(deepcopy(dict(record)))
#         return data
# 
#     def load(self, data, record_cls):
#         """Load a record from the source document of an Elasticsearch hit.
# 
#         The job of this method, is to create a record of type ``record_cls``
#         based on the input ``data``.
# 
#         :param data: A Python dictionary representing the data to load.
#         :param records_cls: The record class to be constructed.
#         :returns: A instance of ``record_cls``.
#         """
#         raise NotImplementedError()
# 
# Path: invenio_records/errors.py
# class MissingModelError(RecordsError):
#     """Error raised when a record has no model."""
# 
# Path: invenio_records/models.py
# class RecordMetadata(db.Model, RecordMetadataBase):
#     """Represent a record metadata."""
# 
#     __tablename__ = 'records_metadata'
# 
#     # Enables SQLAlchemy-Continuum versioning
#     __versioned__ = {}
# 
# Path: invenio_records/signals.py



# Path: invenio_records/api.py
import inspect
import warnings
from copy import deepcopy
from flask import current_app
from invenio_db import db
from jsonpatch import apply_patch
from sqlalchemy.orm.attributes import flag_modified
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy_continuum.utils import parent_class
from werkzeug.local import LocalProxy
from .dictutils import clear_none, dict_lookup
from .dumpers import Dumper
from .errors import MissingModelError
from .models import RecordMetadata
from .signals import after_record_delete, after_record_insert, \
    after_record_revert, after_record_update, before_record_delete, \
    before_record_insert, before_record_revert, before_record_update

            )

        return self

    def delete(self, force=False):
        """Delete a record.

        If `force` is ``False``, the record is soft-deleted: record data will
        be deleted but the record identifier and the history of the record will
        be kept. This ensures that the same record identifier cannot be used
        twice, and that you can still retrieve its history. If `force` is
        ``True``, then the record is completely deleted from the database.

        #. Send a signal :data:`invenio_records.signals.before_record_delete`
           with the current record as parameter.

        #. Delete or soft-delete the current record.

        #. Send a signal :data:`invenio_records.signals.after_record_delete`
           with the current deleted record as parameter.

        :param force: if ``True``, completely deletes the current record from
               the database, otherwise soft-deletes it.
        :returns: The deleted :class:`Record` instance.
        """
        if self.model is None:
            raise MissingModelError()

        with db.session.begin_nested():
            if self.send_signals:

                before_record_delete.send(