rally-openstack/rally_openstack/_compat.py

200 lines
6.0 KiB
Python

# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import importlib
import importlib.abc
import importlib.machinery
import importlib.util
import sys
import warnings
class _MoveSpec(object):
def __init__(self, deprecated, new, release):
"""init moved module info
:param deprecated: a module name that is deprecated
:param new: a module name that should be used instead
:param release: A release when the module was deprecated
"""
self.deprecated = deprecated
self.new = new
self.deprecated_path = self.deprecated.replace(".", "/")
self.new_path = self.new.replace(".", "/")
self.release = release
def get_new_name(self, fullname):
"""Get the new name for deprecated module."""
return fullname.replace(self.deprecated, self.new)
def get_deprecated_path(self, path):
"""Get a path to the deprecated module."""
return path.replace(self.new_path, self.deprecated_path)
_MOVES = [
_MoveSpec(
deprecated="rally_openstack.embedcharts",
new="rally_openstack.task.ui.charts",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.cleanup",
new="rally_openstack.task.cleanup",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.contexts",
new="rally_openstack.task.contexts",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.hook",
new="rally_openstack.task.hooks",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.scenario",
new="rally_openstack.task.scenario",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.scenarios",
new="rally_openstack.task.scenarios",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.types",
new="rally_openstack.task.types",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.platforms",
new="rally_openstack.environment.platforms",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.service",
new="rally_openstack.common.service",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.services",
new="rally_openstack.common.services",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.validators",
new="rally_openstack.common.validators",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.wrappers",
new="rally_openstack.common.wrappers",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.credential",
new="rally_openstack.common.credential",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.osclients",
new="rally_openstack.common.osclients",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.consts",
new="rally_openstack.common.consts",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.exceptions",
new="rally_openstack.common.exceptions",
release="2.0.0"
),
_MoveSpec(
deprecated="rally_openstack.cfg",
new="rally_openstack.common.cfg",
release="2.0.0"
),
]
class ModuleLoader(object):
def __init__(self, move_spec):
self.move_spec = move_spec
def create_module(self, spec):
# Python interpreter will use the default module creator in case of
# None return value.
return None
def exec_module(self, module):
"""Module executor."""
full_name = self.move_spec.get_new_name(module.__name__)
original_module = importlib.import_module(full_name)
if original_module.__file__.endswith("__init__.py"):
# NOTE(andreykurilin): In case we need to list submodules the
# next code can be used:
#
# import pkgutil
#
# for m in pkgutil.iter_modules(original_module.__path__):
# module.__dict__[m.name] = importlib.import_module(
# f"{full_name}.{m.name}")
module.__path__ = [
self.move_spec.get_deprecated_path(original_module.__path__[0])
]
for item in dir(original_module):
if item.startswith("_"):
continue
module.__dict__[item] = original_module.__dict__[item]
module.__file__ = self.move_spec.get_deprecated_path(
original_module.__file__)
return module
class ModulesMovementsHandler(importlib.abc.MetaPathFinder):
@classmethod
def _process_spec(cls, fullname, spec):
"""Make module spec and print warning message if needed."""
if spec.deprecated == fullname:
warnings.warn(
f"Module {fullname} is deprecated since rally-openstack "
f"{spec.release}. Use {spec.get_new_name(fullname)} instead.",
stacklevel=3
)
return importlib.machinery.ModuleSpec(fullname, ModuleLoader(spec))
@classmethod
def find_spec(cls, fullname, path=None, target=None):
"""This functions is what gets executed by the loader."""
for spec in _MOVES:
if spec.deprecated in fullname:
return cls._process_spec(fullname, spec)
def init():
"""Adds our custom module loader."""
sys.meta_path.append(ModulesMovementsHandler())