0
1

More than 3 years have passed since last update.

バグ: PyDrive で RedirectMissingLocation 例外が発生する(Python/Colaboratory)

Last updated at Posted at 2021-07-17

Colaboratory から、大きなサイズのファイルを、PyDrive を使って Google ドライブにアップロードしようとすると、RedirectMissingLocation 例外が発生して失敗する。
回避方法はこちら

問題の詳細

サンプルコードは以下のリンクを参照。
外部データ: ローカル ファイル、ドライブ、スプレッドシート、Cloud Storage - Colaboratory
> Google ドライブ > PyDrive

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials

auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)

なお、投稿時点(2021.7.17)でインストールされていた PyDrive のバージョンは 1.3.1詳細)。
Colaboratory 上にあるファイルを Google ドライブにアップロードするには、次のようにする。

dfile = drive.CreateFile()
dfile.SetContentFile("path.to.large.file")
dfile.Upload()

ここで path.to.large.file のファイルサイズが大きいと、RedirectMissingLocation 例外が発生して失敗する(詳細)。

RedirectMissingLocation: Redirected but the response is missing a Location: header.

原因と回避方法

原因は PyDrive が依存している httplib2 のバグのようである。
詳細は以下の issue を参照。
httplib2 v0.16.0 breaks the library · Issue #803 · googleapis/google-api-python-client · GitHub

この issue に書かれているように、httplib2 をダウングレードすることで回避できる可能性がある。
なお、投稿時点でインストールされていた httplib2 のバージョンは 0.17.4詳細)。

pip install -U httplib2==0.15.0

ダウングレードが終わったら、ランタイムを再起動すること。


例外の詳細


---------------------------------------------------------------------------

RedirectMissingLocation                   Traceback (most recent call last)

<ipython-input-34-d2b7f6f09d2e> in <module>()
      1 dfile = drive.CreateFile()
      2 dfile.SetContentFile("path.to.large.file")
----> 3 dfile.Upload()

10 frames

/usr/local/lib/python3.7/dist-packages/pydrive/files.py in Upload(self, param)
    283         self._FilesPatch(param=param)
    284     else:
--> 285       self._FilesInsert(param=param)
    286 
    287   def Trash(self, param=None):

/usr/local/lib/python3.7/dist-packages/pydrive/auth.py in _decorated(self, *args, **kwargs)
     73       self.http = self.auth.Get_Http_Object()
     74 
---> 75     return decoratee(self, *args, **kwargs)
     76   return _decorated
     77 

/usr/local/lib/python3.7/dist-packages/pydrive/files.py in _FilesInsert(self, param)
    367         param['media_body'] = self._BuildMediaBody()
    368       metadata = self.auth.service.files().insert(**param).execute(
--> 369         http=self.http)
    370     except errors.HttpError as error:
    371       raise ApiRequestError(error)

/usr/local/lib/python3.7/dist-packages/googleapiclient/_helpers.py in positional_wrapper(*args, **kwargs)
    132                 elif positional_parameters_enforcement == POSITIONAL_WARNING:
    133                     logger.warning(message)
--> 134             return wrapped(*args, **kwargs)
    135 
    136         return positional_wrapper

/usr/local/lib/python3.7/dist-packages/googleapiclient/http.py in execute(self, http, num_retries)
    877             body = None
    878             while body is None:
--> 879                 _, body = self.next_chunk(http=http, num_retries=num_retries)
    880             return body
    881 

/usr/local/lib/python3.7/dist-packages/googleapiclient/_helpers.py in positional_wrapper(*args, **kwargs)
    132                 elif positional_parameters_enforcement == POSITIONAL_WARNING:
    133                     logger.warning(message)
--> 134             return wrapped(*args, **kwargs)
    135 
    136         return positional_wrapper

/usr/local/lib/python3.7/dist-packages/googleapiclient/http.py in next_chunk(self, http, num_retries)
   1056             try:
   1057                 resp, content = http.request(
-> 1058                     self.resumable_uri, method="PUT", body=data, headers=headers
   1059                 )
   1060             except:

/usr/local/lib/python3.7/dist-packages/oauth2client/transport.py in new_request(uri, method, body, headers, redirections, connection_type)
    173         resp, content = request(orig_request_method, uri, method, body,
    174                                 clean_headers(headers),
--> 175                                 redirections, connection_type)
    176 
    177         # A stored token may expire between the time it is retrieved and

/usr/local/lib/python3.7/dist-packages/oauth2client/transport.py in request(http, uri, method, body, headers, redirections, connection_type)
    280     return http_callable(uri, method=method, body=body, headers=headers,
    281                          redirections=redirections,
--> 282                          connection_type=connection_type)
    283 
    284 

/usr/local/lib/python3.7/dist-packages/httplib2/__init__.py in request(self, uri, method, body, headers, redirections, connection_type)
   1989                         headers,
   1990                         redirections,
-> 1991                         cachekey,
   1992                     )
   1993         except Exception as e:

/usr/local/lib/python3.7/dist-packages/httplib2/__init__.py in _request(self, conn, host, absolute_uri, request_uri, method, body, headers, redirections, cachekey)
   1688                             ),
   1689                             response,
-> 1690                             content,
   1691                         )
   1692                     # Fix-up relative redirects (which violate an RFC 2616 MUST)

RedirectMissingLocation: Redirected but the response is missing a Location: header.

バージョンの詳細

PyDrive==1.3.1
  - google-api-python-client [required: >=1.2, installed: 1.12.8]
    - google-api-core [required: >=1.21.0,<2dev, installed: 1.26.3]
      - google-auth [required: >=1.21.1,<2.0dev, installed: 1.32.1]
        - cachetools [required: >=2.0.0,<5.0, installed: 4.2.2]
        - pyasn1-modules [required: >=0.2.1, installed: 0.2.8]
          - pyasn1 [required: >=0.4.6,<0.5.0, installed: 0.4.8]
        - rsa [required: >=3.1.4,<5, installed: 4.7.2]
          - pyasn1 [required: >=0.1.3, installed: 0.4.8]
        - setuptools [required: >=40.3.0, installed: 57.2.0]
        - six [required: >=1.9.0, installed: 1.15.0]
      - googleapis-common-protos [required: >=1.6.0,<2.0dev, installed: 1.53.0]
        - protobuf [required: >=3.12.0, installed: 3.17.3]
          - six [required: >=1.9, installed: 1.15.0]
      - packaging [required: >=14.3, installed: 21.0]
        - pyparsing [required: >=2.0.2, installed: 2.4.7]
      - protobuf [required: >=3.12.0, installed: 3.17.3]
        - six [required: >=1.9, installed: 1.15.0]
      - pytz [required: Any, installed: 2018.9]
      - requests [required: >=2.18.0,<3.0.0dev, installed: 2.23.0]
        - certifi [required: >=2017.4.17, installed: 2021.5.30]
        - chardet [required: >=3.0.2,<4, installed: 3.0.4]
        - idna [required: >=2.5,<3, installed: 2.10]
        - urllib3 [required: >=1.21.1,<1.26,!=1.25.1,!=1.25.0, installed: 1.24.3]
      - setuptools [required: >=40.3.0, installed: 57.2.0]
      - six [required: >=1.13.0, installed: 1.15.0]
    - google-auth [required: >=1.16.0, installed: 1.32.1]
      - cachetools [required: >=2.0.0,<5.0, installed: 4.2.2]
      - pyasn1-modules [required: >=0.2.1, installed: 0.2.8]
        - pyasn1 [required: >=0.4.6,<0.5.0, installed: 0.4.8]
      - rsa [required: >=3.1.4,<5, installed: 4.7.2]
        - pyasn1 [required: >=0.1.3, installed: 0.4.8]
      - setuptools [required: >=40.3.0, installed: 57.2.0]
      - six [required: >=1.9.0, installed: 1.15.0]
    - google-auth-httplib2 [required: >=0.0.3, installed: 0.0.4]
      - google-auth [required: Any, installed: 1.32.1]
        - cachetools [required: >=2.0.0,<5.0, installed: 4.2.2]
        - pyasn1-modules [required: >=0.2.1, installed: 0.2.8]
          - pyasn1 [required: >=0.4.6,<0.5.0, installed: 0.4.8]
        - rsa [required: >=3.1.4,<5, installed: 4.7.2]
          - pyasn1 [required: >=0.1.3, installed: 0.4.8]
        - setuptools [required: >=40.3.0, installed: 57.2.0]
        - six [required: >=1.9.0, installed: 1.15.0]
      - httplib2 [required: >=0.9.1, installed: 0.17.4]
      - six [required: Any, installed: 1.15.0]
    - httplib2 [required: >=0.15.0,<1dev, installed: 0.17.4]
    - six [required: >=1.13.0,<2dev, installed: 1.15.0]
    - uritemplate [required: >=3.0.0,<4dev, installed: 3.0.1]
  - oauth2client [required: >=4.0.0, installed: 4.1.3]
    - httplib2 [required: >=0.9.1, installed: 0.17.4]
    - pyasn1 [required: >=0.1.7, installed: 0.4.8]
    - pyasn1-modules [required: >=0.0.5, installed: 0.2.8]
      - pyasn1 [required: >=0.4.6,<0.5.0, installed: 0.4.8]
    - rsa [required: >=3.1.4, installed: 4.7.2]
      - pyasn1 [required: >=0.1.3, installed: 0.4.8]
    - six [required: >=1.6.1, installed: 1.15.0]
  - PyYAML [required: >=3.0, installed: 3.13]
0
1
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
0
1