Hi again Jose, Jeff Scudder has just drawn my attention to a pair of excellent articles he's written about exactly this subject: http://code.google.com/appengine/articles/gdata.html http://code.google.com/appengine/articles/more_google_data.html
As the first article points out, you need to call the gdata.alt.appengine.run_on_appengine function on each instance of a gdata.service.GDataService object in order to have it work on App Engine correctly. -Nick Johnson On Mon, May 18, 2009 at 12:29 PM, Nick Johnson (Google) <[email protected]> wrote: > Hi Jose, > > This is a known incompatibility in App Engine. The GData APIs send an > absolute URL to the httplib library where it expects a relative one > (since the host and port was specified in the constructor); the Python > httplib handles this properly, but the App Engine replacement > currently does not. > > -Nick Johnson > > On Fri, May 15, 2009 at 7:32 PM, Jose Vidal <[email protected]> wrote: >> >> I am trying to read a spreadsheet from app engine using text_db and >> authsub. >> >> I read http://code.google.com/appengine/articles/gdata.html and got it >> to work. Then I read >> http://code.google.com/p/gdata-python-client/wiki/AuthSubWithTextDB >> and I tried to merge the two in the file below (step4.py) but when I >> run it locally I get: >> >> Traceback (most recent call last): >> File "/home/jmvidal/share/progs/googleapps/google_appengine/google/ >> appengine/ext/webapp/__init__.py", line 498, in __call__ >> handler.get(*groups) >> File "/home/jmvidal/share/progs/googleapps/google_appengine/ >> glassboard/step4.py", line 56, in get >> session_token = client._GetDocsClient().UpgradeToSessionToken >> (auth_token) #If I don't pass this argument I get a NonAuthSubToken >> File "/home/jmvidal/share/progs/googleapps/google_appengine/ >> glassboard/gdata/service.py", line 866, in UpgradeToSessionToken >> self.SetAuthSubToken(self.upgrade_to_session_token(token)) >> File "/home/jmvidal/share/progs/googleapps/google_appengine/ >> glassboard/gdata/service.py", line 885, in upgrade_to_session_token >> headers={'Content-Type':'application/x-www-form-urlencoded'}) >> File "/home/jmvidal/share/progs/googleapps/google_appengine/ >> glassboard/gdata/auth.py", line 678, in perform_request >> return http_client.request(operation, url, data=data, >> headers=headers) >> File "/home/jmvidal/share/progs/googleapps/google_appengine/ >> glassboard/atom/http.py", line 163, in request >> return connection.getresponse() >> File "/home/jmvidal/share/progs/googleapps/google_appengine/google/ >> appengine/dist/httplib.py", line 200, in getresponse >> self._allow_truncated, self._follow_redirects) >> File "/home/jmvidal/share/progs/googleapps/google_appengine/google/ >> appengine/api/urlfetch.py", line 267, in fetch >> raise DownloadError(str(e)) >> DownloadError: ApplicationError: 2 nonnumeric port: '' >> >> Can anyone shed some light on this? >> >> >> # step4.py >> # >> # Trying to read spreadsheets from app engine using text_db and >> authsub. >> # >> # Merge of this code >> # http://code.google.com/p/gdata-python-client/wiki/AuthSubWithTextDB >> # with this one >> # http://code.google.com/appengine/articles/gdata.html (step 3) >> >> import wsgiref.handlers >> import cgi >> from google.appengine.ext import webapp >> from google.appengine.api import users >> import atom.url >> import gdata.service >> import gdata.alt.appengine >> import gdata.spreadsheet.text_db >> import settings >> >> >> class Fetcher(webapp.RequestHandler): >> >> def get(self): >> # Write our pages title >> self.response.out.write("""<html><head><title> >> Google Data Feed Fetcher: read Google Data API Atom feeds</ >> title>""") >> self.response.out.write('</head><body>') >> next_url = atom.url.Url('http', settings.HOST_NAME, path='/step4') >> # Allow the user to sign in or sign out >> if users.get_current_user(): >> self.response.out.write('<a href="%s">Sign Out</a><br>' % ( >> users.create_logout_url(str(next_url)))) >> else: >> self.response.out.write('<a href="%s">Sign In</a><br>' % ( >> users.create_login_url(str(next_url)))) >> >> # Initialize a client to talk to Google Data API services. >> # client = gdata.service.GDataService() >> # auth_url = client.GenerateAuthSubURL( >> # next_url, >> # ('http://docs.google.com/feeds/',), secure=False, session=True) >> >> client = gdata.spreadsheet.text_db.DatabaseClient() >> auth_url = client._GetDocsClient().GenerateAuthSubURL( >> next_url, >> ('http://spreadsheets.google.com/feeds/','http://docs.google.com/ >> feeds/documents/'), secure=False, session=True) >> >> gdata.alt.appengine.run_on_appengine(client) >> >> feed_url = self.request.get('feed_url') >> >> session_token = None >> # Find the AuthSub token and upgrade it to a session token. >> auth_token = gdata.auth.extract_auth_sub_token_from_url >> (self.request.uri) >> if auth_token: >> # Upgrade the single-use AuthSub token to a multi-use session >> token. >> client._GetDocsClient().SetAuthSubToken(auth_token) >> session_token = client._GetDocsClient().UpgradeToSessionToken >> (auth_token) #If I don't pass this argument I get a NonAuthSubToken >> client._GetSpreadsheetsClient().SetAuthSubToken >> (client._GetDocsClient().GetAuthSubToken()) >> # session_token = client.upgrade_to_session_token(auth_token) >> if session_token and users.get_current_user(): >> # If there is a current user, store the token in the datastore >> and >> # associate it with the current user. Since we told the client >> to >> # run_on_appengine, the add_token call will automatically store >> the >> # session token if there is a current_user. >> client.token_store.add_token(session_token) >> elif session_token: >> # Since there is no current user, we will put the session token >> # in a property of the client. We will not store the token in >> the >> # datastore, since we wouldn't know which user it belongs to. >> # Since a new client object is created with each get call, we >> don't >> # need to worry about the anonymous token being used by other >> users. >> client.current_token = session_token >> >> self.response.out.write('<div id="main">') >> self.fetch_feed(client, feed_url) >> self.response.out.write('</div>') >> self.response.out.write( >> '<div id="sidebar"><div id="scopes"><h4>Request a token</ >> h4><ul>') >> self.response.out.write('<li><a href="%s">Google Documents</a></ >> li>' % (auth_url)) >> self.response.out.write('</ul></div><br/><div id="tokens">') >> >> def fetch_feed(self, client, feed_url): >> # Attempt to fetch the feed. >> if not feed_url: >> self.response.out.write( >> 'No feed_url was specified for the app to fetch.<br/>') >> example_url = atom.url.Url('http', settings.HOST_NAME, path='/ >> step4', >> params={'feed_url': >> 'http://docs.google.com/feeds/documents/private/full'} >> ).to_string() >> self.response.out.write('Here\'s an example query which will >> show the' >> ' XML for the feed listing your Google Documents <a ' >> 'href="%s">%s</a>' % (example_url, example_url)) >> return >> try: >> response = client.Get(feed_url, converter=str) >> self.response.out.write(cgi.escape(response)) >> except gdata.service.RequestError, request_error: >> # If fetching fails, then tell the user that they need to login >> to >> # authorize this app by logging in at the following URL. >> if request_error[0]['status'] == 401: >> # Get the URL of the current page so that our AuthSub request >> will >> # send the user back to here. >> next = atom.url.Url('http', settings.HOST_NAME, path='/step4', >> params={'feed_url': feed_url}) >> # If there is a current user, we can request a session token, >> otherwise >> # we should ask for a single use token. >> auth_sub_url = client.GenerateAuthSubURL(next, feed_url, >> secure=False, session=True) >> self.response.out.write('<a href="%s">' % (auth_sub_url)) >> self.response.out.write( >> 'Click here to authorize this application to view the >> feed</a>') >> else: >> self.response.out.write( >> 'Something went wrong, here is the error object: %s ' % ( >> str(request_error[0]))) >> >> >> def main(): >> application = webapp.WSGIApplication([('/.*', Fetcher),], >> debug=True) >> wsgiref.handlers.CGIHandler().run(application) >> >> >> if __name__ == '__main__': >> main() >> >> --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Google App Engine" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/google-appengine?hl=en -~----------~----~----~----~------~----~------~--~---
