def migrate(no_version=False, use_env=None, uid=None, context=None):
    """
    This is the decorator for the migrate() function
    in migration scripts.

    Set argument `no_version` to True if the method has to be taken into
    account if the module is installed during a migration.

    Set argument `use_env` if you want an v8+ environment instead of a plain
    cursor. Starting from version 10, this is the default

    The arguments `uid` and `context` can be set when an evironment is
    requested. In the cursor case, they're ignored.

    The migration function's signature must be `func(cr, version)` if
    `use_env` is `False` or not set and the version is below 10, or
    `func(env, version)` if `use_env` is `True` or not set and the version is
    10 or higher.

    Return when the `version` argument is not defined and `no_version` is
    False and log execeptions.

    Retrieve debug context data from the frame above for
    logging purposes.
    """
    def wrap(func):
        def wrapped_function(cr, version):
            stage = 'unknown'
            module = 'unknown'
            filename = 'unknown'
            with ExitStack() as contextmanagers:
                contextmanagers.enter_context(savepoint(cr))
                use_env2 = use_env is None and version_info[0] >= 10 or use_env
                if use_env2:
                    assert version_info[0] >= 8, 'you need at least v8'
                    contextmanagers.enter_context(api.Environment.manage())
                try:
                    frame = inspect.getargvalues(inspect.stack()[1][0])
                    stage = frame.locals['stage']
                    module = frame.locals['pkg'].name
                    # Python3: fetch pyfile from locals, not fp
                    filename = frame.locals.get(
                        'pyfile') or frame.locals['fp'].name
                except Exception as e:
                    logger.error(
                        "'migrate' decorator: failed to inspect "
                        "the frame above: %s" % e)
                    pass
                if not version and not no_version:
                    return
                logger.info(
                    "%s: %s-migration script called with version %s" %
                    (module, stage, version))
                try:
                    # The actual function is called here
                    func(
                        api.Environment(
                            cr, uid or SUPERUSER_ID, context or {})
                        if use_env2 else cr, version)
                except Exception as e:
                    message = repr(e) if sys.version_info[0] == 2 else str(e)
                    logger.error(
                        "%s: error in migration script %s: %s",
                        module, filename, message)
                    logger.exception(e)
                    raise
        return wrapped_function
    return wrap