2012-02-19 20 views
15

Sto cercando di creare file in una cartella Dropbox.com da un'applicazione GAE. Ho eseguito tutti i passaggi per registrare un'applicazione Dropbox e installato l'SDK Python da Dropbox localmente sul mio computer di sviluppo. (vedi API dropbox.com). Tutto funziona perfettamente quando uso lo script di test cli_client.py nel SDK set sulla mia macchina locale per accedere set - file can 'put' eccScrittura di file sull'account Dropbox da GAE

ora voglio iniziare a lavorare in un ambiente GAE, così le cose si fanno un po 'complicato. Qualche aiuto sarebbe utile.

Per chi ha familiarità con il codice API di Dropbox, ho avuto i seguenti problemi così lontane:

Issue 1

Il modulo API Dropbox rest.py utilizza pkg_resources per ottenere il certs installate nel sito- pacchetti di un'installazione locale della macchina. Ho sostituito

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

con

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

e messo il file cert nella mia directory dell'applicazione GAE. Forse questo non è giusto; vedi il mio codice di errore di autenticazione qui sotto.

Issue 2

Il modulo API Dropbox session.py utilizza oauth modulo, così ho cambiato l'inclusione di AppEngine oauth.

Tuttavia, ha sollevato un'eccezione che l'oauth di GAE non ha il metodo OAuthConsumer utilizzato dal modulo session.py di Dropbox. Quindi ho scaricato oauth 1.0 e aggiunto alla mia applicazione e ora importa questo invece di GAE oauth.

Issue 3

modulo SSL GAE non sembra avere proprietà CERT_REQUIRED.

Questa è una costante, così ho cambiato

self.cert_reqs = ssl.CERT_REQUIRED 

a

self.cert_reqs = 2 

Questo è usato quando si chiama

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

autenticazione Errore

Ma ancora non è possibile connettersi a 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')] 
+0

spero che qualcuno risponde a questa. Nel frattempo, mentre non sono sicuro di cosa sia pkg_resources.resource_filename(), penso che restituisca un nome file, non un file aperto, mentre file() apre il file con nome e restituisce un oggetto stream (file aperto). Potresti voler provare 'TRUSTED_CERT_FILE = 'trusted-certs.crt''. –

+0

Grazie Guido - proverò che – erickCo

+0

Guido, sei corretto, il tipo restituito da 'pkg_resources.resource_filename()' è 'str'. Il valore è il percorso completo del file certs. Così ho fatto il cambiamento come suggerisci tu. Ahimè, ancora lo stesso errore. – erickCo

risposta

7

Ecco la mia versione modificata di Dropbox Python SDK 1.4 che funziona bene per me con Python 2.7 GAE: dropbox_python_sdk_gae_patched.7z.base64. Non sono necessarie librerie aggiuntive di terze parti, solo quelle fornite dall'ambiente GAE.

Viene testato solo il caricamento di file (put_file). Ecco i passaggi di configurazione:

  1. Estrarre l'archivio nella cartella principale dell'applicazione GAE (se l'app principale si trova nella cartella principale). È possibile decodificare BASE64 utilizzando Base64 Encoder/Decoder: base64.exe -d dropbox_python_sdk_gae_patched.7z.base64 dropbox_python_sdk_gae_patched.7z.
  2. Impostazione APP_KEY, APP_SECRET, ACCESS_TYPE, ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET. I primi tre sono configurati al momento della creazione dell'applicazione dropbox. Gli ultimi due si ottengono quando si concede l'accesso all'applicazione a specifici account Dropbox, è possibile ottenerli attraverso cli_client.py (dal DB Python SDK) dal file token_store.txt.
  3. Uso nel codice come questo:

    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))) 
    
+1

Puoi aggiornare questo al nuovissimo sdk dropbox, quello che ha DropboxOAuth2FlowNoRedirect? –

3

ho con successo caricato da Google AppEngine al set con la mia versione patchata del Dropbox SDK: https://github.com/cklein/dropbox-client-python

L'utilizzo di urllib2 è stato sostituito da huTools.http: https://github.com/hudora/huTools/

Questo è il codice che si chiama in un gestore di richieste:

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() 
1

ho patchato alla versione Dropbox Python SDK 2.2 per lavorare su Google App Engine. Si prega di trovare il codice qui rilevante:

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

La patch relativo codice (copiato da github) per rest.py è qui:

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) 
2

A partire da aprile 2016, nessuno degli altri suggerimenti funziona . (Dropbox API versione 2, Python SDK versione 6.2).

Se avete solo bisogno alcune delle funzioni SDK, l'ho trovato più semplice utilizzare solo l'API HTTP direttamente:

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) 
Problemi correlati