Я застрял с этим в течение нескольких дней, пока не смог найти никакого решения, если есть какие-либо python эксперты, пожалуйста, помогите мне.
Я получаю данные от azure api, в данном случае получаем объект машины, который имеет информацию об этом компьютере.
Сначала у меня есть эта функция, которая возвращает мне ComputeManagementClient с кредитами:
def get_azure_compute_client():
creds, subscription = get_azure_credentials()
if "az_compute_client" not in g:
g.az_compute_client = ComputeManagementClient(creds, subscription)
return g.az_compute_client
Затем у меня есть Функция, которая использует этот клиент для получения машинного объекта:
@retry(stop=stop_after_attempt(3))
@cache.memoize(60)
def get_azure_machine_info(rg_name, machine_name, expand="instanceView"):
try:
compute_client = get_azure_compute_client()
return (compute_client.virtual_machines.get(rg_name, machine_name, expand=expand))
except CloudError:
return None
Если вы заметили, что я использую кеш, и вот откуда возникла проблема, прежде чем все мои тесты прошли, но теперь они дают мне PicklingError
, должно быть решение этой проблемы, я не хочу игнорировать декоратор, я хочу проверить функцию, а затем я хочу проверить, работает ли кэш, дважды вызвав функцию и заявив, что она была вызывается один раз.
Это мой тестовый пример:
@patch("dev_maintenance.machines.get_azure_compute_client")
def test_get_azure_machine_info (get_azure_compute_client):
with app.app_context():
ret = get_azure_machine_info("rg1", "m1")
assert len(get_azure_compute_client.return_value.method_calls) == 1
assert (ret == get_azure_compute_client.return_value.machines.virtual_machines.get.return_value)
get_azure_compute_client.return_value.virtual_machines.get.assert_called_once_with(
"rg1", "m1", expand="instanceView")
Ошибка:
self = <Retrying object at 0x10641e310 (stop=<tenacity.stop.stop_after_attempt object at 0x10637c790>, wait=<tenacity.wait.wa...bject at 0x1063adf50>, before=<function before_nothing at 0x10639d320>, after=<function after_nothing at 0x1063b0680>)>
fn = <function get_azure_machine_info at 0x10641d680>, args = ('rg1', 'm1'), kwargs = {}, retry_state = <tenacity.RetryCallState object at 0x106552ad0>, do = <tenacity.DoAttempt object at 0x106552b90>
def call(self, fn, *args, **kwargs):
self.begin(fn)
retry_state = RetryCallState(
retry_object=self, fn=fn, args=args, kwargs=kwargs)
while True:
do = self.iter(retry_state=retry_state)
if isinstance(do, DoAttempt):
try:
> result = fn(*args, **kwargs)
../../venv/lib/python3.7/site-packages/tenacity/__init__.py:361:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
args = ('rg1', 'm1'), kwargs = {}, cache_key = '9dcgFgzh/7XqPDLnkUe92F', rv = <MagicMock name='get_azure_compute_client().virtual_machines.get()' id='4401267984'>, found = False
@functools.wraps(f)
def decorated_function(*args, **kwargs):
#: bypass cache
if self._bypass_cache(unless, f, *args, **kwargs):
return f(*args, **kwargs)
try:
cache_key = decorated_function.make_cache_key(
f, *args, **kwargs
)
if (
callable(forced_update)
and (
forced_update(*args, **kwargs)
if wants_args(forced_update)
else forced_update()
)
is True
):
rv = None
found = False
else:
rv = self.cache.get(cache_key)
found = True
# If the value returned by cache.get() is None, it
# might be because the key is not found in the cache
# or because the cached value is actually None
if rv is None:
# If we're sure we don't need to cache None values
# (cache_none=False), don't bother checking for
# key existence, as it can lead to false positives
# if a concurrent call already cached the
# key between steps. This would cause us to
# return None when we shouldn't
if not cache_none:
found = False
else:
found = self.cache.has(cache_key)
except Exception:
if self.app.debug:
raise
logger.exception("Exception possibly due to cache backend.")
return f(*args, **kwargs)
if not found:
rv = f(*args, **kwargs)
if response_filter is None or response_filter(rv):
try:
self.cache.set(
cache_key,
rv,
> timeout=decorated_function.cache_timeout,
)
../../venv/lib/python3.7/site-packages/flask_caching/__init__.py:841:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <flask_caching.backends.simple.SimpleCache object at 0x105871410>, key = '9dcgFgzh/7XqPDLnkUe92F', value = <MagicMock name='get_azure_compute_client().virtual_machines.get()' id='4401267984'>, timeout = 60
def set(self, key, value, timeout=None):
expires = self._normalize_timeout(timeout)
self._prune()
self._cache[key] = (
expires,
> pickle.dumps(value, pickle.HIGHEST_PROTOCOL),
)
E _pickle.PicklingError: Can't pickle <class 'unittest.mock.MagicMock'>: it's not the same object as unittest.mock.MagicMock
../../venv/lib/python3.7/site-packages/flask_caching/backends/simple.py:76: PicklingError
The above exception was the direct cause of the following exception:
get_azure_compute_client = <MagicMock name='get_azure_compute_client' id='4400427728'>
@patch("dev_maintenance.machines.get_azure_compute_client")
def test_get_azure_machine_info (get_azure_compute_client):
with app.app_context():
> ret = get_azure_machine_info("rg1", "m1")
dev_maintenance/tests/test_machines.py:113:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../venv/lib/python3.7/site-packages/tenacity/__init__.py:292: in wrapped_f
return self.call(f, *args, **kw)
../../venv/lib/python3.7/site-packages/tenacity/__init__.py:358: in call
do = self.iter(retry_state=retry_state)
../../venv/lib/python3.7/site-packages/tenacity/__init__.py:332: in iter
six.raise_from(retry_exc, fut.exception())
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
value = None, from_value = PicklingError("Can't pickle <class 'unittest.mock.MagicMock'>: it's not the same object as unittest.mock.MagicMock")
> ???
E tenacity.RetryError: RetryError[<Future at 0x106565850 state=finished raised PicklingError>]
<string>:3: RetryError