首页 > 解决方案 > freeze_time `ignore` 似乎不适用于更复杂的设置(Django + S3 / boto)

问题描述

我使用带有 S3 的 Django 作为文件存储(使用 boto3/botocore 库)。我有一个创建一些 Django 实例的“管理”命令——我使用 freezegun,所以这些实例似乎是在过去创建的。但是,其中一些模型包含正在保存到 S3 的文件 - 这会引发一些异常:

...
  File "/home/rado/.virtualenvs/twisto/lib/python3.6/site-packages/botocore/client.py", line 314, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/home/rado/.virtualenvs/twisto/lib/python3.6/site-packages/botocore/client.py", line 612, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (RequestTimeTooSkewed) when calling the ListObjectsV2 operation: The difference between the request time and the current time is too large.

这是由于botocore.auth模块中的一些身份验证代码检查时间差异。我尝试使用ignore参数 ( freeze_time(datetime_in_past, ignore=['botocore'])) 来解决这个问题,但它没有帮助,botocore.auth仍然使用FakeDatetime(我使用带有断点的调试器来查明问题)。

我试图用一个简单的可重现的例子来重现这个问题,所以我想出了以下内容:

# test.py
from freezegun import freeze_time
from datetime import datetime
import stuff_in_between

import test_time #  <-- note this unused import

with freeze_time(datetime(2019, 1, 1, 1, 1, 1, 1), ignore=['test_time']):
    print(f'frozen time: {datetime.now()}')
    stuff_in_between.call_test_time()
# stuff_in_between.py
def call_test_time():
    import test_time
    test_time.test_time()
# test_time.py
from datetime import datetime

def test_time():
    print(f'real datetime.now: {datetime.now()}')

此代码正常工作, freeze_time 忽略test_time并打印real datetime.now: <real time>. 但是,如果我忽略了标记为未使用的导入test.py,它就不起作用 - freeze_time 不是ignore模块并且脚本会打印出来real datetime.now: <fake time>

我想我可以在我真正的 Django go 中尝试类似的东西,所以我做了以下操作:

...
import botocore
import botocore.auth
# hell, try to import everything possible related to S3
with freeze_time(datetime_in_past, ignore=['botocore']:
   ...
   # create some instances, that also save files to S3

无论我导入或忽略什么,这都不起作用,botocore.auth仍然继续使用FakeDatetime......是否有错误freezegun?还是我以某种方式滥用图书馆?为什么它会这样?

只是为了澄清-我不关心使用时间偏移设置的文件。它们可以在 S3 中实时设置。我只关心用冻结时间保存的模型。所以如果我有以下模型:

class Image(models.Model):
    date_created = models.DateTimeField(auto_now_add=True)
    file = models.ImageField(...)

字段date_created将使用冻结时间。

标签: pythondjangoamazon-s3python-importfreezegun

解决方案


推荐阅读