pytest - 如何使用 S3FileSystem、Pytest 和 Moto 访问我自己的假存储桶

标签 pytest moto python-s3fs

我正在尝试使用 Pytest、Moto (4.1.6) 和 s3fs (0.4.2) 为与 S3 交互的函数实现单元测试。

到目前为止,我能够创建一个存储桶并用 data 中的所有文件填充它。文件夹。

不幸的是,我的要求之一是我需要使用s3fs.core.S3FileSystem object访问存储桶。类,因为这就是我们内部库的工作方式,我试图尽可能接近原始环境。

如果我在尝试访问假存储桶时没有遇到访问被拒绝的情况,那就不成问题了。

这是来自 conftest.py 的相关代码

#!/usr/bin/env python3

from moto import mock_s3
from pathlib import Path

import boto3
import os
import pytest
import s3fs


@pytest.fixture(scope="session")
def test_data_folder():
    return os.path.join(os.path.dirname(__file__), "data")


@pytest.fixture(scope="session")
@mock_s3
def s3_filesystem(test_data_folder):
    connection = boto3.client("s3", region_name="us-east-1")
    connection.create_bucket(Bucket="bucket")

    for path in Path(test_data_folder).rglob("*"):
        if path.is_file():
            with open(path, "rb") as parquet:
               data = parquet.read()
               connection.put_object(Bucket="bucket", Key=str(path), Body=data)

    bucket = boto3.resource("s3").Bucket("bucket")
    for object in bucket.objects.all():
        print(object.key)

    filesystem = s3fs.S3FileSystem(anon=True)
    filesystem.ls(test_data_folder)
    return filesystem

运行此代码后,我可以在打印输出中看到其中存在几个如下所示的文件: /Users/campos/repos/project/tests/data/20221027/transactions_test_20221027.parquet

我想返回s3fs.core.S3FileSystem object根据我的测试,但是当我尝试运行 filesystem.ls(test_data_folder) 时在我的调试器中我得到 *** PermissionError: All access to this object has been disabled

再深入一点,从 objects.bucket.all() 返回的对象看起来像这样: s3.ObjectSummary(bucket_name='bucket', key='/Users/campos/repos/project/tests/data/20221027/orders_test_20221027.parquet')

我已经尝试将公共(public)访问控制列表添加到存储桶创建中,如下所示 s3.create_bucket(Bucket="bucket", ACL="public-read")但它并没有改变任何东西。

我还在错误消息中看到了这一点:

api_params = {'Bucket': 'Users', 'Delimiter': '/', 'EncodingType': 'url', 'Prefix': 'ykb595/repos/gfctr-card-lob-pyexetl/tests/data/'}

...

botocore.errorfactory.NoSuchBucket: An error occurred (NoSuchBucket) when calling the ListObjectsV2 operation: The specified bucket does not exist

很明显,我的文件存在于某种存储桶中的某个位置,但看起来好像无法找到该存储桶。

我错过了什么?

提前谢谢您!!

最佳答案

将此 filesystem.ls(test_data_folder) 更改为 filesystem.ls("bucket")

test_data_folder 解析为 home/username/.. (对我来说),这意味着 S3FS 尝试查找名为 home 的存储桶。但是您在其他地方使用的存储桶名称是bucket


目前,S3/Moto 中创建的存储桶结构如下所示: / -> home/ -> folder1/ -> folder2/ -> 等等

我认为 S3FS 不太喜欢这个,无论是结构本身还是第一个文件夹名为 / 的事实。当删除 mock_s3 装饰器并针对 AWS 本身进行测试时,对 filesystem.ls(bucket_name) 的调用严重失败,并且 filesystem.walk()返回相同的奇怪结果。 ([('桶', [], [''])])

当我在 S3 中创建平面结构时,filesystem.walk() 确实按预期工作(针对 AWS 和 Moto):

# Create files using only the last section of the path:
with open(path, "rb") as parquet:
    data = parquet.read()
    connection.put_object(Bucket=bucket_name, Key=path.parts[-1], Body=data)

结果:

[('/bucket', [], ['file1.py', 'file2.py', 'file3.py'])]

一般来说,您要求按照最佳实践更好地理解、研究和实现 AWS 测试

如果您不确定预期结果,我的建议始终是首先针对 AWS 验证行为。 S3FS 和 Moto 等开源工具非常适合编写单元测试,并验证已知行为不会改变。 但如果您不知道预期的结果,您就永远无法确定您所看到的奇怪的事情是 S3FS、Moto 还是 AWS 的结果。

关于pytest - 如何使用 S3FileSystem、Pytest 和 Moto 访问我自己的假存储桶,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75902766/

相关文章:

python - Pandas read_csv 指定 AWS 配置文件

python - 如何将 pytest.mark 装饰器包装在另一个装饰器中并维护所有属性?

mongodb - 如何用MongoDB(Motor)实现FastAPI的pytest

python - 如何让 pytest2 和 pytest3 并存?

python - 使用 Py.Test 测量特定文件的单元测试覆盖率

python - 如何模拟 AWS DynamoDB 服务?

amazon-s3 - 使用 Moto 将 s3 存储桶模拟为 IAM 用户

python - 如何在 Python/Django 中使用 AWS SNS (boto3/moto) 测试 SMS?