diff --git a/neutron/common/utils.py b/neutron/common/utils.py index 8b50967ff26..021ebbb1dcf 100644 --- a/neutron/common/utils.py +++ b/neutron/common/utils.py @@ -22,9 +22,11 @@ import collections import decimal import errno import functools +import importlib import math import multiprocessing import os +import os.path import random import signal import socket @@ -46,6 +48,7 @@ from oslo_utils import importutils import six from stevedore import driver +import neutron from neutron._i18n import _, _LE from neutron.db import api as db_api @@ -693,3 +696,33 @@ def extract_exc_details(e): if args is _NO_ARGS_MARKER: return details return details % args + + +def import_modules_recursively(topdir): + '''Import and return all modules below the topdir directory.''' + modules = [] + for root, dirs, files in os.walk(topdir): + for file_ in files: + if file_[-3:] != '.py': + continue + + module = file_[:-3] + if module == '__init__': + continue + + import_base = root.replace('/', '.') + + # NOTE(ihrachys): in Python3, or when we are not located in the + # directory containing neutron code, __file__ is absolute, so we + # should truncate it to exclude PYTHONPATH prefix + prefixlen = len(os.path.dirname(neutron.__file__)) + import_base = 'neutron' + import_base[prefixlen:] + + module = '.'.join([import_base, module]) + if module not in sys.modules: + importlib.import_module(module) + modules.append(module) + + for dir_ in dirs: + modules.extend(import_modules_recursively(dir_)) + return modules diff --git a/neutron/db/migration/models/head.py b/neutron/db/migration/models/head.py index 9cdf2662302..33d0a33e8ba 100644 --- a/neutron/db/migration/models/head.py +++ b/neutron/db/migration/models/head.py @@ -21,10 +21,9 @@ Based on this comparison database can be healed with healing migration. """ -# TODO(ihrachys): move the module under neutron/tests - import os.path +from neutron.common import utils from neutron.db import address_scope_db # noqa from neutron.db import agents_db # noqa from neutron.db import agentschedulers_db # noqa @@ -63,10 +62,9 @@ from neutron.plugins.ml2 import models as ml2_models # noqa from neutron.services.auto_allocate import models as aa_models # noqa from neutron.services.segments import db # noqa from neutron.services.trunk import models as trunk_models # noqa -from neutron.tests import tools -tools.import_modules_recursively(os.path.dirname(models.__file__)) +utils.import_modules_recursively(os.path.dirname(models.__file__)) def get_metadata(): diff --git a/neutron/tests/tools.py b/neutron/tests/tools.py index f0fa8c32f18..52892e49fe3 100644 --- a/neutron/tests/tools.py +++ b/neutron/tests/tools.py @@ -14,15 +14,14 @@ # under the License. import copy -import importlib import os import platform import random import string -import sys import time import warnings +from debtcollector import moves import fixtures import mock import netaddr @@ -30,10 +29,10 @@ from neutron_lib import constants import six import unittest2 -import neutron from neutron.api.v2 import attributes from neutron.common import constants as n_const from neutron.common import ipv6_utils +from neutron.common import utils from neutron.db import common_db_mixin @@ -132,9 +131,6 @@ class CommonDbMixinHooksFixture(fixtures.Fixture): common_db_mixin.CommonDbMixin._model_query_hooks = self.original_hooks -from neutron.common import utils - - def setup_mock_calls(mocked_call, expected_calls_and_values): """A convenient method to setup a sequence of mock calls. @@ -204,36 +200,6 @@ class UnorderedList(list): return not self == other -def import_modules_recursively(topdir): - '''Import and return all modules below the topdir directory.''' - modules = [] - for root, dirs, files in os.walk(topdir): - for file_ in files: - if file_[-3:] != '.py': - continue - - module = file_[:-3] - if module == '__init__': - continue - - import_base = root.replace('/', '.') - - # NOTE(ihrachys): in Python3, or when we are not located in the - # directory containing neutron code, __file__ is absolute, so we - # should truncate it to exclude PYTHONPATH prefix - prefixlen = len(os.path.dirname(neutron.__file__)) - import_base = 'neutron' + import_base[prefixlen:] - - module = '.'.join([import_base, module]) - if module not in sys.modules: - importlib.import_module(module) - modules.append(module) - - for dir_ in dirs: - modules.extend(import_modules_recursively(dir_)) - return modules - - def get_random_string(n=10): return ''.join(random.choice(string.ascii_lowercase) for _ in range(n)) @@ -333,3 +299,8 @@ def reset_random_seed(): def get_random_ipv6_mode(): return random.choice(n_const.IPV6_MODES) + + +import_modules_recursively = moves.moved_function( + utils.import_modules_recursively, 'import_modules_recursively', __name__, + version='Newton', removal_version='Ocata') diff --git a/neutron/tests/unit/common/test_utils.py b/neutron/tests/unit/common/test_utils.py index 737e1275542..c8326c381ef 100644 --- a/neutron/tests/unit/common/test_utils.py +++ b/neutron/tests/unit/common/test_utils.py @@ -13,7 +13,9 @@ # under the License. import errno +import os.path import re +import sys import eventlet import mock @@ -30,6 +32,7 @@ from neutron.plugins.common import constants as p_const from neutron.plugins.common import utils as plugin_utils from neutron.tests import base from neutron.tests.common import helpers +from neutron.tests.unit import tests class TestParseMappings(base.BaseTestCase): @@ -778,3 +781,14 @@ class TestExcDetails(base.BaseTestCase): def test_extract_exc_details_no_details_attached(self): self.assertIsInstance( utils.extract_exc_details(Exception()), six.text_type) + + +class ImportModulesRecursivelyTestCase(base.BaseTestCase): + + def test_object_modules(self): + example_module = 'neutron.tests.unit.tests.example.dir.example_module' + sys.modules.pop(example_module, None) + modules = utils.import_modules_recursively( + os.path.dirname(tests.__file__)) + self.assertIn(example_module, modules) + self.assertIn(example_module, sys.modules) diff --git a/neutron/tests/unit/objects/test_objects.py b/neutron/tests/unit/objects/test_objects.py index 8fb316eb948..2820d2dd52b 100644 --- a/neutron/tests/unit/objects/test_objects.py +++ b/neutron/tests/unit/objects/test_objects.py @@ -18,9 +18,9 @@ import pprint from oslo_versionedobjects import base as obj_base from oslo_versionedobjects import fixture +from neutron.common import utils from neutron import objects from neutron.tests import base as test_base -from neutron.tests import tools # NOTE: The hashes in this list should only be changed if they come with a @@ -55,7 +55,7 @@ class TestObjectVersions(test_base.BaseTestCase): super(TestObjectVersions, self).setUp() # NOTE(ihrachys): seed registry with all objects under neutron.objects # before validating the hashes - tools.import_modules_recursively(os.path.dirname(objects.__file__)) + utils.import_modules_recursively(os.path.dirname(objects.__file__)) def test_versions(self): checker = fixture.ObjectVersionChecker( diff --git a/neutron/tests/unit/tests/test_tools.py b/neutron/tests/unit/tests/test_tools.py deleted file mode 100644 index 1ab3e939fda..00000000000 --- a/neutron/tests/unit/tests/test_tools.py +++ /dev/null @@ -1,33 +0,0 @@ -# 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 os -import sys - -from neutron.tests import base -from neutron.tests import tools -from neutron.tests.unit import tests # noqa - - -EXAMPLE_MODULE = 'neutron.tests.unit.tests.example.dir.example_module' - - -class ImportModulesRecursivelyTestCase(base.BaseTestCase): - - def test_object_modules(self): - sys.modules.pop(EXAMPLE_MODULE, None) - modules = tools.import_modules_recursively( - os.path.dirname(tests.__file__)) - self.assertIn( - 'neutron.tests.unit.tests.example.dir.example_module', - modules) - self.assertIn(EXAMPLE_MODULE, sys.modules)