Тестирование с дополнительным импортом в Python - PullRequest
1 голос
/ 21 марта 2020

У меня есть библиотека, которая может использовать два модуля; один работает быстро, но доступен только на Linux и macOS, другой медленнее, но он мультиплатформенный. Мое решение состояло в том, чтобы сделать библиотеку совместимой с обоими и иметь что-то вроде следующего:

try:
    import fastmodule
except ImportError:
    import slowmodule

Теперь я хочу сравнить синхронизацию библиотеки при использовании любого модуля. Есть ли способ маскировки fastmodule без изменения исходного кода (т.е. в блокноте Jupyter) в среде, где установлены оба модуля, так что используется slowmodule?

1 Ответ

1 голос
/ 23 марта 2020

Это что-то вроде хака, но здесь это так:
Вы можете написать свой собственный импортер и зарегистрировать его (обратите внимание, что это Python 3-специфицировано c, Python 2 имел другой API для этого):

import sut
import functools
import importlib
import sys


def use_slow(f):
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        ImportRaiser.use_slow = True
        if 'fastmodule' in sys.modules:
            del sys.modules['fastmodule']  # otherwise it will remain cached
        importlib.reload(sut)
        f(*args, **kwargs)

    return wrapped


def use_fast(f):
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        ImportRaiser.use_slow = False
        importlib.reload(sut)
        f(*args, **kwargs)

    return wrapped


class ImportRaiser:
    use_slow = False

    def find_spec(self, fullname, path, target=None):
        if fullname == 'fastmodule':
            if self.use_slow:
                raise ImportError()


sys.meta_path.insert(0, ImportRaiser())

@use_fast
def test_fast():
    # test code


@use_slow
def test_slow():
    # test code

Здесь sut - это тестируемый модуль, который необходимо перезагрузить, чтобы изменить поведение. Я добавил декораторы для читабельности, но, конечно, это может быть сделано с помощью некоторой функции или в настройках теста.

Если вы используете медленную версию, fastmodule повысит ImportError при импорте и slowmodule будет использоваться вместо В «быстром» случае все работает как обычно.

...