はじめに
PythonsからS3をいじる際に、これまではaws cliを直接叩いていたのですが、s3fsを使用するとexistsやlsみたいなわかりやすい名称で使えるというのをどこかで知ったので使ってみた。
同名でS3をマウントするもの( https://github.com/s3fs-fuse/s3fs-fuse )もあるようですが、本記事でのs3fs( https://github.com/dask/s3fs )とは別物です。
で、キャッシュのせいかファイルを置いた直後にexistsするとFalseだったりと整合性がとれなくてハマった話です。
s3fsとは
リポジトリTOPには下記のように記載されています。
S3FS builds on boto3 to provide a convenient Python filesystem interface for S3.
Google翻訳すると↓
S3FSはboto3をベースにしており、S3用の便利なPythonファイルシステムインタフェースを提供します。
「はじめに」にも書きましたが、同名でS3をマウントするものもあるようですが、別物です。
むしろ、GitHubの☆を見てもマウントする奴が3000以上、本題の方が130位なので、どちらかというとこの記事に書くライブラリの方が無名。
使い方
インストールして(詳細)
pip install s3fs
以下のように書けばOK
import s3fs
fs = s3fs.S3FileSystem(anon=True)
list = fs.ls('my-bucket')
ドキュメントがしっかりしているので、以下に気をつければ?簡単に使えて良いです。
が、気をつけるなんて現実的ではないので個人的にはあまりオススメしません。
ハマったことと対応方法
内容としては、ファイル配置後に上位のフォルダを見た際にFileNotFoundErrorになるという事。
で、キャッシュが悪さしているので、キャッシュを更新すれば正しく動作します。
(キャッシュ更新するにはlsのrefreshオプションをTrueにする)
具体的には下記のコード参照。
(実際に試したい場合には↓↓に全コード書いたので、そちらをオススメ。)
import s3fs
fs = s3fs.S3FileSystem(key=key, secret=secret)
output_path = '{}/hoge/{}'.format(s3_path, 'test.txt')
fs.put('./test.txt', output_path)
try:
fs.ls(s3_path)
except FileNotFoundError:
print('ls : FileNotFoundError')
if not fs.exists(s3_path):
print('exists : False')
try:
fs.rm(s3_path, recursive=True)
except FileNotFoundError:
print('rm : FileNotFoundError')
try:
fs.ls(s3_path, refresh=True)
print('ls : refreshしたら例外なし')
except FileNotFoundError:
pass
if fs.exists(s3_path):
print('exists : refresh後はTrue')
try:
fs.ls(s3_path)
print('ls : FileNotFoundErrorは発生しない')
except FileNotFoundError:
pass
考察とか
全コード
import s3fs
key = 'xxxxxxxxxx'
secret = 'yyyyyyyyyyyyyyy'
s3_path = 'my-bucket/aaa/bbb'
try:
fs.ls(s3_path, refresh=True)
fs.rm(s3_path, recursive=True)
except FileNotFoundError:
pass
try:
fs.ls(s3_path)
except FileNotFoundError:
pass
try:
fs.ls('{}/{}'.format(s3_path, 'hoge'))
except FileNotFoundError:
pass
output_path = '{}/hoge/{}'.format(s3_path, 'test.txt')
fs.put('./test.txt', output_path)
try:
fs.ls(output_path)
print('ls : FileNotFoundErrorは発生しない')
except FileNotFoundError:
pass
if fs.exists(output_path):
print('exists : True')
try:
fs.ls(s3_path)
except FileNotFoundError:
print('ls : FileNotFoundError')
if not fs.exists(s3_path):
print('exists : False')
try:
fs.rm(s3_path, recursive=True)
except FileNotFoundError:
print('rm : FileNotFoundError')
try:
fs.ls(s3_path, refresh=True)
print('ls : refreshしたら例外なし')
except FileNotFoundError:
pass
if fs.exists(s3_path):
print('exists : refresh後はTrue')
try:
fs.ls(s3_path)
print('ls : FileNotFoundErrorは発生しない')
except FileNotFoundError:
pass
参考URL