17

GAEアプリケーションからDropbox.comフォルダーにファイルを作成しようとしています。Dropboxアプリケーションを登録するためのすべての手順を実行し、DropboxからPythonSDKを開発マシンにローカルにインストールしました。(dropbox.com APIを参照してください)。ローカルマシンのdropboxSDKでcli_client.pyテストスクリプトを使用してdropboxにアクセスすると、すべてが完全に機能します。ファイルなどを「配置」できます。

私は今GAE環境で働き始めたいので、物事は少しトリッキーになります。いくつかの助けが役立つでしょう。

Dropbox APIコードに精通している人のために、これまでに次の問題がありました。

問題1

rest.py Dropbox APIモジュールは、pkg_resourcesを使用して、ローカルマシンインストールのサイトパッケージにインストールされている証明書を取得します。交換しました

TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt')

TRUSTED_CERT_FILE = file('trusted-certs.crt')

証明書ファイルをGAEアプリケーションディレクトリに配置しました。おそらく、これは完全には正しくありません。以下の私の認証エラーコードを参照してください。

第2号

session.py Dropbox APIモジュールはoauthモジュールを使用するため、インクルードをappengineoauthに変更しました。

ただし、GAEのoauthにはDropboxsession.pyモジュールで使用されるOAuthConsumerメソッドがないという例外が発生しました。そこで、oauth 1.0をダウンロードしてアプリケーションに追加し、GAEoauthの代わりにこれをインポートします。

問題3

GAEsslモジュールにCERT_REQUIREDプロパティがないようです。

これは定数なので、変更しました

self.cert_reqs = ssl.CERT_REQUIRED

self.cert_reqs = 2

これは、呼び出すときに使用されます

ssl.wrap_socket(sock, cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)

認証エラー

しかし、それでもDropboxに接続できません。

Status: 401
Reason: Unauthorized
Body: {"error": "Authentication failed"}
Headers: [('date', 'Sun, 19 Feb 2012 15:11:12 GMT'), ('transfer-encoding', 'chunked'), ('connection', 'keep-alive'), ('content-type', 'application/json'), ('server', 'dbws')]
4

4 に答える 4

7

これが、Python2.7GAEでうまく機能するDropboxPythonSDK 1.4のパッチバージョンです:dropbox_python_sdk_gae_patched.7z.base64。追加のサードパーティライブラリは必要ありません。GAE環境によって提供されるものだけです。

ファイルのアップロード(put_file)のみがテストされます。セットアップ手順は次のとおりです。

  1. アーカイブをGAEアプリケーションのルートフォルダーに解凍します(メインアプリがルートフォルダーにある場合)。Base64エンコーダー/デコーダーを使用してBASE64をデコードできます:base64.exe -d dropbox_python_sdk_gae_patched.7z.base64 dropbox_python_sdk_gae_patched.7z
  2. APP_KEY、APP_SECRET、ACCESS_TYPE、ACCESS_TOKEN_KEY、ACCESS_TOKEN_SECRETを設定します。最初の3つは、ドロップボックスアプリケーションの作成時に構成されます。最後の2つは、特定のドロップボックスアカウントへのアプリケーションアクセスを許可するときに取得されます。これらは、token_store.txtファイルのcli_client.py(DB Python SDKから)を介して取得できます。
  3. 次のようなコードで使用します。

    import dropbox
    # ...
    def DropboxUpload(path, data):
        sess = dropbox.session.DropboxSession(APP_KEY, APP_SECRET, ACCESS_TYPE)
        sess.set_token(ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET)
        cli = dropbox.client.DropboxClient(sess)
        data_file = StringIO.StringIO(data)
        return cli.put_file(path, data_file)
    # ...
    import json
    class DropboxUploadHandlerExample(webapp2.RequestHandler):
        def get(self):
            url = "http://www.google.com/"
            result = urlfetch.fetch(url)
            self.response.headers['Content-Type'] = 'application/json'
            self.response.out.write(json.dumps(DropboxUpload('/fetch_result.dat', result.content)))
    
于 2012-04-22T00:04:43.390 に答える
3

パッチを適用した独自のバージョンのDropboxSDKを使用してGoogleAppengineからDropboxに正常にアップロードしました:https ://github.com/cklein/dropbox-client-python

urllib2の使用法はhuTools.httpに置き換えられました:https ://github.com/hudora/huTools/

これは、リクエストハンドラーで呼び出されるコードです。

    db_client = dropbox.get_dropbox_client(consumer_key='', consumer_secret='', access_token_key='', access_token_secret='')
    fileobj = StringIO.StringIO(data)
    path = '/some/path/filename'
    resp = db_client.put_file(path, fileobj)
    fileobj.close()
于 2012-03-01T14:53:40.257 に答える
3

2016年4月の時点で、他の提案はいずれも機能しません。(Dropbox APIバージョン2、Python SDKバージョン6.2)。

SDK関数のいくつかだけが必要な場合は、HTTPAPIを直接使用するのが最も簡単であることがわかりました。

def files_upload(f, path, mode='add', autorename=False, mute=False):

    args = {
        'path': path,
        'mode': mode,
        'autorename': autorename,
        'mute': mute,
    }

    headers = {
        'Authorization': 'Bearer {}'.format(ACCESS_TOKEN),
        'Dropbox-API-Arg': json.dumps(args),
        'Content-Type': 'application/octet-stream',
    }

    request = urllib2.Request('https://content.dropboxapi.com/2/files/upload', f, headers=headers)
    r = urllib2.urlopen(request)
于 2016-04-29T12:35:38.803 に答える
1

GoogleAppEngineで動作するようにDropboxPythonSDKバージョン2.2にパッチを適用しました。ここで関連するコードを見つけてください:

https://github.com/duncanhawthorne/gae-dropbox-python

rest.pyに関連するコードパッチ(githubからコピー)は次のとおりです。

 import io
 import pkg_resources
-import socket
+#import socket
 import ssl
 import sys
 import urllib
+import urllib2

+def mock_urlopen(method,url,body,headers,preload_content):
+    request = urllib2.Request(url, body, headers=headers)
+    r = urllib2.urlopen(request)
+    return r         
+    
 try:
     import json
 except ImportError:
 @@ -23,7 +29,10 @@

 SDK_VERSION = "2.2.0"

-TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt')
+try:
+    TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt')
+except:
+    TRUSTED_CERT_FILE = file('trusted-certs.crt')


 class RESTResponse(io.IOBase):
 @@ -125,6 +134,7 @@ def flush(self):
         pass

 def create_connection(address):
+    return
     host, port = address
     err = None
     for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
 @@ -152,7 +162,7 @@ def json_loadb(data):


 class RESTClientObject(object):
-    def __init__(self, max_reusable_connections=8, mock_urlopen=None):
+    def __init__(self, max_reusable_connections=8, mock_urlopen=mock_urlopen):
         """
         Parameters
             max_reusable_connections
 @@ -206,7 +216,7 @@ def request(self, method, url, post_params=None, body=None, headers=None, raw_re
                 raise ValueError("headers should not contain newlines (%s: %s)" %
                                  (key, value))

-        try:
+        if True:
             # Grab a connection from the pool to make the request.
             # We return it to the pool when caller close() the response
             urlopen = self.mock_urlopen if self.mock_urlopen else self.pool_manager.urlopen
 @@ -217,14 +227,14 @@ def request(self, method, url, post_params=None, body=None, headers=None, raw_re
                 headers=headers,
                 preload_content=False
             )
-            r = RESTResponse(r) # wrap up the urllib3 response before proceeding
-        except socket.error as e:
-            raise RESTSocketError(url, e)
-        except urllib3.exceptions.SSLError as e:
-            raise RESTSocketError(url, "SSL certificate error: %s" % e)
+            #r = RESTResponse(r) # wrap up the urllib3 response before proceeding
+        #except socket.error as e:
+        #    raise RESTSocketError(url, e)
+        #except urllib3.exceptions.SSLError as e:
+        #    raise RESTSocketError(url, "SSL certificate error: %s" % e)

-        if r.status not in (200, 206):
-            raise ErrorResponse(r, r.read())
+        #if r.status not in (200, 206):
+        #    raise ErrorResponse(r, r.read())

         return self.process_response(r, raw_response)

 @@ -321,10 +331,11 @@ def PUT(cls, *n, **kw):
         return cls.IMPL.PUT(*n, **kw)


-class RESTSocketError(socket.error):
+class RESTSocketError():
     """A light wrapper for ``socket.error`` that adds some more information."""

     def __init__(self, host, e):
+        return
         msg = "Error connecting to \"%s\": %s" % (host, str(e))
         socket.error.__init__(self, msg)
于 2015-08-17T18:28:35.780 に答える