LoginSignup
3
2

More than 1 year has passed since last update.

ValueError: ('Iterator has already started', <google.api_core.page_iterator.HTTPIterator object at 0xaaaaaaa>)

Last updated at Posted at 2022-01-14

pythonでCloud Storageのファイル数を数えようとしたらこんなエラーがでました。
なんなんだと。

  File "/........./lib64/python3.6/site-packages/google/api_core/page_iterator.py", line 227, in __iter__
    raise ValueError("Iterator has already started", self)
ValueError: ('Iterator has already started', <google.api_core.page_iterator.HTTPIterator object at 0x7fc844c4aeb8>)

そもそものコードはこちらです。
やりたいことは

  • 対象フォルダのファイルを探す。
  • ファイルが無ければ終了。
  • ファイルがあればファイル名を表示する。 というものです。
from google.cloud import storage
import sys

storage_client = storage.Client()
bucket = storage_client.bucket(BUCKET_NAME)

### 集計対象のファイルを探す
blobs = bucket.list_blobs(
  prefix=TARGET_GCS_FOLDER + '/hoge_'
)

if len(list(blobs)) == 0:
  print("Error, No target files....")
  sys.exit(1)

for item in blobs:  # <--- ここ!!!
  print(item.name)

そんでどうやらエラーの箇所はblobオブジェクトをイテレートしてファイル名を表示するところでした。

なぜかと?

どうやらblobオブジェクトのイテレーターは1回しか使えないみたいです。
File "/........./lib64/python3.6/site-packages/google/api_core/page_iterator.py"についてコードを見てみると

class Iterator(object):
...................
    def __init__(
        self,
        client,
        item_to_value=_item_to_value_identity,
        page_token=None,
        max_results=None,
    ):
        self._started = False # <--- ここ!!
        self.client = client
.......................
    def __iter__(self):
        """Iterator for each item returned.

        Returns:
            types.GeneratorType[Any]: A generator of items from the API.

        Raises:
            ValueError: If the iterator has already been started.
        """
        if self._started:
            raise ValueError("Iterator has already started", self)  # <--- ここ!!!
        self._started = True
        return self._items_iter()

とあります。
一度__iter__が呼ばれてしまうとself._startedがTrueになりValueErrorがなってしまうことがわかります。

ここで最初の__iter__ですが

if len(list(blobs)) == 0:

でリスト数を数えています。このlist(...)で__iter__が呼ばれているので、すでにself._startedがTrueとなっていたわけです。

なので一度別のリスト型変数に入れなおしてからやればエラーになりません。

blob_list_obj = list(blobs)

if len(blob_list_obj) == 0:
  print("Error, No target files....")
  sys.exit(1)

for item in blob_list_obj:
  print(item.name)

参考ページ

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2