PageRenderTime 49ms CodeModel.GetById 18ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 1ms

/gdata/docs/client.py

http://radioappz.googlecode.com/
Python | 608 lines | 570 code | 12 blank | 26 comment | 7 complexity | 0e0aee6b0154368514d5a393394f5f38 MD5 | raw file
  1#!/usr/bin/python
  2#
  3# Copyright 2009 Google Inc. All Rights Reserved.
  4#
  5# Licensed under the Apache License, Version 2.0 (the "License");
  6# you may not use this file except in compliance with the License.
  7# You may obtain a copy of the License at
  8#
  9#      http://www.apache.org/licenses/LICENSE-2.0
 10#
 11# Unless required by applicable law or agreed to in writing, software
 12# distributed under the License is distributed on an "AS IS" BASIS,
 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14# See the License for the specific language governing permissions and
 15# limitations under the License.
 16
 17"""DocsClient extends gdata.client.GDClient to streamline DocList API calls."""
 18
 19
 20__author__ = 'e.bidelman (Eric Bidelman)'
 21
 22import mimetypes
 23import urllib
 24import atom.data
 25import atom.http_core
 26import gdata.client
 27import gdata.docs.data
 28import gdata.gauth
 29
 30
 31# Feed URI templates
 32DOCLIST_FEED_URI = '/feeds/default/private/full/'
 33FOLDERS_FEED_TEMPLATE = DOCLIST_FEED_URI + '%s/contents'
 34ACL_FEED_TEMPLATE = DOCLIST_FEED_URI + '%s/acl'
 35REVISIONS_FEED_TEMPLATE = DOCLIST_FEED_URI + '%s/revisions'
 36
 37
 38class DocsClient(gdata.client.GDClient):
 39  """Client extension for the Google Documents List API."""
 40
 41  host = 'docs.google.com'  # default server for the API
 42  api_version = '3.0'  # default major version for the service.
 43  auth_service = 'writely'
 44  auth_scopes = gdata.gauth.AUTH_SCOPES['writely']
 45
 46  def __init__(self, auth_token=None, **kwargs):
 47    """Constructs a new client for the DocList API.
 48
 49    Args:
 50      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
 51          OAuthToken which authorizes this client to edit the user's data.
 52      kwargs: The other parameters to pass to gdata.client.GDClient constructor.
 53    """
 54    gdata.client.GDClient.__init__(self, auth_token=auth_token, **kwargs)
 55
 56  def get_file_content(self, uri, auth_token=None, **kwargs):
 57    """Fetches the file content from the specified uri.
 58
 59    This method is useful for downloading/exporting a file within enviornments
 60    like Google App Engine, where the user does not have the ability to write
 61    the file to a local disk.
 62
 63    Args:
 64      uri: str The full URL to fetch the file contents from.
 65      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
 66          OAuthToken which authorizes this client to edit the user's data.
 67      kwargs: Other parameters to pass to self.request().
 68
 69    Returns:
 70      The binary file content.
 71
 72    Raises:
 73      gdata.client.RequestError: on error response from server.
 74    """
 75    server_response = self.request('GET', uri, auth_token=auth_token, **kwargs)
 76    if server_response.status != 200:
 77      raise  gdata.client.RequestError, {'status': server_response.status,
 78                                         'reason': server_response.reason,
 79                                         'body': server_response.read()}
 80    return server_response.read()
 81
 82  GetFileContent = get_file_content
 83
 84  def _download_file(self, uri, file_path, auth_token=None, **kwargs):
 85    """Downloads a file to disk from the specified URI.
 86
 87    Note: to download a file in memory, use the GetFileContent() method.
 88
 89    Args:
 90      uri: str The full URL to download the file from.
 91      file_path: str The full path to save the file to.
 92      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
 93          OAuthToken which authorizes this client to edit the user's data.
 94      kwargs: Other parameters to pass to self.get_file_content().
 95
 96    Raises:
 97      gdata.client.RequestError: on error response from server.
 98    """
 99    f = open(file_path, 'wb')
100    try:
101      f.write(self.get_file_content(uri, auth_token=auth_token, **kwargs))
102    except gdata.client.RequestError, e:
103      f.close()
104      raise e
105    f.flush()
106    f.close()
107
108  _DownloadFile = _download_file
109
110  def get_doclist(self, uri=None, limit=None, auth_token=None, **kwargs):
111    """Retrieves the main doclist feed containing the user's items.
112
113    Args:
114      uri: str (optional) A URI to query the doclist feed.
115      limit: int (optional) A maximum cap for the number of results to
116          return in the feed. By default, the API returns a maximum of 100
117          per page. Thus, if you set limit=5000, you will get <= 5000
118          documents (guarenteed no more than 5000), and will need to follow the
119          feed's next links (feed.GetNextLink()) to the rest. See
120          get_everything(). Similarly, if you set limit=50, only <= 50
121          documents are returned. Note: if the max-results parameter is set in
122          the uri parameter, it is chosen over a value set for limit.
123      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
124          OAuthToken which authorizes this client to edit the user's data.
125      kwargs: Other parameters to pass to self.get_feed().
126
127    Returns:
128      gdata.docs.data.DocList feed.
129    """
130    if uri is None:
131      uri = DOCLIST_FEED_URI
132
133    if isinstance(uri, (str, unicode)):
134      uri = atom.http_core.Uri.parse_uri(uri)    
135
136    # Add max-results param if it wasn't included in the uri.
137    if limit is not None and not 'max-results' in uri.query:
138      uri.query['max-results'] = limit
139
140    return self.get_feed(uri, desired_class=gdata.docs.data.DocList,
141                         auth_token=auth_token, **kwargs)
142
143  GetDocList = get_doclist
144
145  def get_doc(self, resource_id, etag=None, auth_token=None, **kwargs):
146    """Retrieves a particular document given by its resource id.
147
148    Args:
149      resource_id: str The document/item's resource id. Example spreadsheet:
150          'spreadsheet%3A0A1234567890'.
151      etag: str (optional) The document/item's etag value to be used in a
152          conditional GET. See http://code.google.com/apis/documents/docs/3.0/
153          developers_guide_protocol.html#RetrievingCached.
154      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
155          OAuthToken which authorizes this client to edit the user's data.
156      kwargs: Other parameters to pass to self.get_entry().
157
158    Returns:
159      A gdata.docs.data.DocsEntry object representing the retrieved entry.
160
161    Raises:
162      ValueError if the resource_id is not a valid format.
163    """
164    match = gdata.docs.data.RESOURCE_ID_PATTERN.match(resource_id)
165    if match is None:
166      raise ValueError, 'Invalid resource id: %s' % resource_id
167    return self.get_entry(
168        DOCLIST_FEED_URI + resource_id, etag=etag,
169        desired_class=gdata.docs.data.DocsEntry,
170        auth_token=auth_token, **kwargs)
171
172  GetDoc = get_doc
173
174  def get_everything(self, uri=None, auth_token=None, **kwargs):
175    """Retrieves the user's entire doc list.
176
177    The method makes multiple HTTP requests (by following the feed's next links)
178    in order to fetch the user's entire document list.
179
180    Args:
181      uri: str (optional) A URI to query the doclist feed with.
182      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
183          OAuthToken which authorizes this client to edit the user's data.
184      kwargs: Other parameters to pass to self.GetDocList().
185
186    Returns:
187      A list of gdata.docs.data.DocsEntry objects representing the retrieved
188      entries.
189    """
190    if uri is None:
191      uri = DOCLIST_FEED_URI
192
193    feed = self.GetDocList(uri=uri, auth_token=auth_token, **kwargs)
194    entries = feed.entry
195
196    while feed.GetNextLink() is not None:
197      feed = self.GetDocList(
198          feed.GetNextLink().href, auth_token=auth_token, **kwargs)
199      entries.extend(feed.entry)
200
201    return entries
202
203  GetEverything = get_everything
204
205  def get_acl_permissions(self, resource_id, auth_token=None, **kwargs):
206    """Retrieves a the ACL sharing permissions for a document.
207
208    Args:
209      resource_id: str The document/item's resource id. Example for pdf:
210          'pdf%3A0A1234567890'.
211      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
212          OAuthToken which authorizes this client to edit the user's data.
213      kwargs: Other parameters to pass to self.get_feed().
214
215    Returns:
216      A gdata.docs.data.AclFeed object representing the document's ACL entries.
217
218    Raises:
219      ValueError if the resource_id is not a valid format.
220    """
221    match = gdata.docs.data.RESOURCE_ID_PATTERN.match(resource_id)
222    if match is None:
223      raise ValueError, 'Invalid resource id: %s' % resource_id
224
225    return self.get_feed(
226        ACL_FEED_TEMPLATE % resource_id, desired_class=gdata.docs.data.AclFeed,
227        auth_token=auth_token, **kwargs)
228
229  GetAclPermissions = get_acl_permissions
230
231  def get_revisions(self, resource_id, auth_token=None, **kwargs):
232    """Retrieves the revision history for a document.
233
234    Args:
235      resource_id: str The document/item's resource id. Example for pdf:
236          'pdf%3A0A1234567890'.
237      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
238          OAuthToken which authorizes this client to edit the user's data.
239      kwargs: Other parameters to pass to self.get_feed().
240
241    Returns:
242      A gdata.docs.data.RevisionFeed representing the document's revisions.
243
244    Raises:
245      ValueError if the resource_id is not a valid format.
246    """
247    match = gdata.docs.data.RESOURCE_ID_PATTERN.match(resource_id)
248    if match is None:
249      raise ValueError, 'Invalid resource id: %s' % resource_id
250
251    return self.get_feed(
252        REVISIONS_FEED_TEMPLATE % resource_id,
253        desired_class=gdata.docs.data.RevisionFeed, auth_token=auth_token,
254        **kwargs)
255
256  GetRevisions = get_revisions
257
258  def create(self, doc_type, title, folder_or_id=None, writers_can_invite=None,
259             auth_token=None, **kwargs):
260    """Creates a new item in the user's doclist.
261
262    Args:
263      doc_type: str The type of object to create. For example: 'document',
264          'spreadsheet', 'folder', 'presentation'.
265      title: str A title for the document.
266      folder_or_id: gdata.docs.data.DocsEntry or str (optional) Folder entry or
267          the resouce id of a folder to create the object under. Note: A valid
268          resource id for a folder is of the form: folder%3Afolder_id.
269      writers_can_invite: bool (optional) False prevents collaborators from
270          being able to invite others to edit or view the document.
271      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
272          OAuthToken which authorizes this client to edit the user's data.
273      kwargs: Other parameters to pass to self.post().
274
275    Returns:
276      gdata.docs.data.DocsEntry containing information newly created item.
277    """
278    entry = gdata.docs.data.DocsEntry(title=atom.data.Title(text=title))
279    entry.category.append(gdata.docs.data.make_kind_category(doc_type))
280
281    if isinstance(writers_can_invite, gdata.docs.data.WritersCanInvite):
282      entry.writers_can_invite = writers_can_invite
283    elif isinstance(writers_can_invite, bool):
284      entry.writers_can_invite = gdata.docs.data.WritersCanInvite(
285          value=str(writers_can_invite).lower())
286
287    uri = DOCLIST_FEED_URI
288
289    if folder_or_id is not None:
290      if isinstance(folder_or_id, gdata.docs.data.DocsEntry):
291        # Verify that we're uploading the resource into to a folder.
292        if folder_or_id.get_document_type() == gdata.docs.data.FOLDER_LABEL:
293          uri = folder_or_id.content.src
294        else:
295          raise gdata.client.Error, 'Trying to upload item to a non-folder.'
296      else:
297        uri = FOLDERS_FEED_TEMPLATE % folder_or_id
298
299    return self.post(entry, uri, auth_token=auth_token, **kwargs)
300
301  Create = create
302
303  def copy(self, source_entry, title, auth_token=None, **kwargs):
304    """Copies a native Google document, spreadsheet, or presentation.
305
306    Note: arbitrary file types and PDFs do not support this feature.
307
308    Args:
309      source_entry: gdata.docs.data.DocsEntry An object representing the source
310          document/folder.
311      title: str A title for the new document.
312      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
313          OAuthToken which authorizes this client to edit the user's data.
314      kwargs: Other parameters to pass to self.post().
315
316    Returns:
317      A gdata.docs.data.DocsEntry of the duplicated document.
318    """
319    entry = gdata.docs.data.DocsEntry(
320        title=atom.data.Title(text=title),
321        id=atom.data.Id(text=source_entry.GetSelfLink().href))
322    return self.post(entry, DOCLIST_FEED_URI, auth_token=auth_token, **kwargs)
323
324  Copy = copy
325
326  def move(self, source_entry, folder_entry=None,
327           keep_in_folders=False, auth_token=None, **kwargs):
328    """Moves an item into a different folder (or to the root document list).
329
330    Args:
331      source_entry: gdata.docs.data.DocsEntry An object representing the source
332          document/folder.
333      folder_entry: gdata.docs.data.DocsEntry (optional) An object representing
334          the destination folder. If None, set keep_in_folders to
335          True to remove the item from all parent folders.
336      keep_in_folders: boolean (optional) If True, the source entry
337          is not removed from any existing parent folders it is in.
338      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
339          OAuthToken which authorizes this client to edit the user's data.
340      kwargs: Other parameters to pass to self.post().
341
342    Returns:
343      A gdata.docs.data.DocsEntry of the moved entry or True if just moving the
344      item out of all folders (e.g. Move(source_entry)).
345    """
346    entry = gdata.docs.data.DocsEntry(id=source_entry.id)
347
348    # Remove the item from any folders it is already in.
349    if not keep_in_folders:
350      for folder in source_entry.InFolders():
351        self.delete(
352            '%s/contents/%s' % (folder.href, source_entry.resource_id.text),
353            force=True)
354
355    # If we're moving the resource into a folder, verify it is a folder entry.
356    if folder_entry is not None:
357      if folder_entry.get_document_type() == gdata.docs.data.FOLDER_LABEL:
358        return self.post(entry, folder_entry.content.src,
359                         auth_token=auth_token, **kwargs)
360      else:
361        raise gdata.client.Error, 'Trying to move item into a non-folder.'
362
363    return True
364
365  Move = move
366
367  def upload(self, media, title, folder_or_uri=None, content_type=None,
368             auth_token=None, **kwargs):
369    """Uploads a file to Google Docs.
370
371    Args:
372      media: A gdata.data.MediaSource object containing the file to be
373          uploaded or a string of the filepath.
374      title: str The title of the document on the server after being
375          uploaded.
376      folder_or_uri: gdata.docs.data.DocsEntry or str (optional) An object with
377          a link to the folder or the uri to upload the file to.
378          Note: A valid uri for a folder is of the form:
379                /feeds/default/private/full/folder%3Afolder_id/contents
380      content_type: str (optional) The file's mimetype. If not provided, the
381          one in the media source object is used or the mimetype is inferred
382          from the filename (if media is a string). When media is a filename,
383          it is always recommended to pass in a content type.
384      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
385          OAuthToken which authorizes this client to edit the user's data.
386      kwargs: Other parameters to pass to self.post().
387
388    Returns:
389      A gdata.docs.data.DocsEntry containing information about uploaded doc.
390    """
391    uri = None
392    if folder_or_uri is not None:
393      if isinstance(folder_or_uri, gdata.docs.data.DocsEntry):
394        # Verify that we're uploading the resource into to a folder.
395        if folder_or_uri.get_document_type() == gdata.docs.data.FOLDER_LABEL:
396          uri = folder_or_uri.content.src
397        else:
398          raise gdata.client.Error, 'Trying to upload item to a non-folder.'
399      else:
400        uri = folder_or_uri
401    else:
402      uri = DOCLIST_FEED_URI
403
404    # Create media source if media is a filepath.
405    if isinstance(media, (str, unicode)):
406      mimetype = mimetypes.guess_type(media)[0]
407      if mimetype is None and content_type is None:
408        raise ValueError, ("Unknown mimetype. Please pass in the file's "
409                           "content_type")
410      else:
411        media = gdata.data.MediaSource(file_path=media,
412                                       content_type=content_type)
413
414    entry = gdata.docs.data.DocsEntry(title=atom.data.Title(text=title))
415
416    return self.post(entry, uri, media_source=media,
417                     desired_class=gdata.docs.data.DocsEntry,
418                     auth_token=auth_token, **kwargs)
419
420  Upload = upload
421
422  def download(self, entry_or_id_or_url, file_path, extra_params=None,
423               auth_token=None, **kwargs):
424    """Downloads a file from the Document List to local disk.
425
426    Note: to download a file in memory, use the GetFileContent() method.
427
428    Args:
429      entry_or_id_or_url: gdata.docs.data.DocsEntry or string representing a
430          resource id or URL to download the document from (such as the content
431          src link).
432      file_path: str The full path to save the file to.
433      extra_params: dict (optional) A map of any further parameters to control
434          how the document is downloaded/exported. For example, exporting a
435          spreadsheet as a .csv: extra_params={'gid': 0, 'exportFormat': 'csv'}
436      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
437          OAuthToken which authorizes this client to edit the user's data.
438      kwargs: Other parameters to pass to self._download_file().
439
440    Raises:
441      gdata.client.RequestError if the download URL is malformed or the server's
442      response was not successful.
443      ValueError if entry_or_id_or_url was a resource id for a filetype
444      in which the download link cannot be manually constructed (e.g. pdf).
445    """
446    if isinstance(entry_or_id_or_url, gdata.docs.data.DocsEntry):
447      url = entry_or_id_or_url.content.src
448    else:
449      if gdata.docs.data.RESOURCE_ID_PATTERN.match(entry_or_id_or_url):
450        url = gdata.docs.data.make_content_link_from_resource_id(
451            entry_or_id_or_url)
452      else:
453        url = entry_or_id_or_url
454
455    if extra_params is not None:
456      if 'exportFormat' in extra_params and url.find('/Export?') == -1:
457        raise gdata.client.Error, ('This entry type cannot be exported '
458                                   'as a different format.')
459
460      if 'gid' in extra_params and url.find('spreadsheets') == -1:
461        raise gdata.client.Error, 'gid param is not valid for this doc type.'
462
463      url += '&' + urllib.urlencode(extra_params)
464
465    self._download_file(url, file_path, auth_token=auth_token, **kwargs)
466
467  Download = download
468
469  def export(self, entry_or_id_or_url, file_path, gid=None, auth_token=None,
470             **kwargs):
471    """Exports a document from the Document List in a different format.
472
473    Args:
474      entry_or_id_or_url: gdata.docs.data.DocsEntry or string representing a
475          resource id or URL to download the document from (such as the content
476          src link).
477      file_path: str The full path to save the file to.  The export
478          format is inferred from the the file extension.
479      gid: str (optional) grid id for downloading a single grid of a
480          spreadsheet. The param should only be used for .csv and .tsv
481          spreadsheet exports.
482      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
483          OAuthToken which authorizes this client to edit the user's data.
484      kwargs: Other parameters to pass to self.download().
485
486    Raises:
487      gdata.client.RequestError if the download URL is malformed or the server's
488      response was not successful.
489    """
490    extra_params = {}
491
492    match = gdata.docs.data.FILE_EXT_PATTERN.match(file_path)
493    if match:
494      extra_params['exportFormat'] = match.group(1)
495
496    if gid is not None:
497      extra_params['gid'] = gid
498
499    self.download(entry_or_id_or_url, file_path, extra_params,
500                  auth_token=auth_token, **kwargs)
501
502  Export = export
503
504
505class DocsQuery(gdata.client.Query):
506
507  def __init__(self, title=None, title_exact=None, opened_min=None,
508               opened_max=None, edited_min=None, edited_max=None, owner=None,
509               writer=None, reader=None, show_folders=None,
510               show_deleted=None, ocr=None, target_language=None,
511               source_language=None, convert=None, **kwargs):
512    """Constructs a query URL for the Google Documents List  API.
513
514    Args:
515      title: str (optional) Specifies the search terms for the title of a
516             document. This parameter used without title_exact will only
517             submit partial queries, not exact queries.
518      title_exact: str (optional) Meaningless without title. Possible values
519                   are 'true' and 'false'. Note: Matches are case-insensitive.
520      opened_min: str (optional) Lower bound on the last time a document was
521                  opened by the current user. Use the RFC 3339 timestamp
522                  format. For example: opened_min='2005-08-09T09:57:00-08:00'.
523      opened_max: str (optional) Upper bound on the last time a document was
524                  opened by the current user. (See also opened_min.)
525      edited_min: str (optional) Lower bound on the last time a document was
526                  edited by the current user. This value corresponds to the
527                  edited.text value in the doc's entry object, which
528                  represents changes to the document's content or metadata.
529                  Use the RFC 3339 timestamp format. For example:
530                  edited_min='2005-08-09T09:57:00-08:00'
531      edited_max: str (optional) Upper bound on the last time a document was
532                  edited by the user. (See also edited_min.)
533      owner: str (optional) Searches for documents with a specific owner. Use
534             the email address of the owner. For example:
535             owner='user@gmail.com'
536      writer: str (optional) Searches for documents which can be written to
537              by specific users. Use a single email address or a comma
538              separated list of email addresses. For example:
539              writer='user1@gmail.com,user@example.com'
540      reader: str (optional) Searches for documents which can be read by
541              specific users. (See also writer.)
542      show_folders: str (optional) Specifies whether the query should return
543                    folders as well as documents. Possible values are 'true'
544                    and 'false'. Default is false.
545      show_deleted: str (optional) Specifies whether the query should return
546                    documents which are in the trash as well as other
547                    documents. Possible values are 'true' and 'false'.
548                    Default is false.
549      ocr: str (optional) Specifies whether to attempt OCR on a .jpg, .png, or
550           .gif upload. Possible values are 'true' and 'false'. Default is
551           false. See OCR in the Protocol Guide: 
552           http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#OCR
553      target_language: str (optional) Specifies the language to translate a
554                       document into. See Document Translation in the Protocol
555                       Guide for a table of possible values:
556                       http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html#DocumentTranslation
557      source_language: str (optional) Specifies the source language of the
558                       original document. Optional when using the translation
559                       service. If not provided, Google will attempt to
560                       auto-detect the source language. See Document
561                       Translation in the Protocol Guide for a table of
562                       possible values (link in target_language).
563      convert: str (optional) Used when uploading arbitrary file types to
564               specity if document-type uploads should convert to a native
565               Google Docs format. Possible values are 'true' and 'false'.
566               The default is 'true'.
567    """
568    gdata.client.Query.__init__(self, **kwargs)
569    self.convert = convert
570    self.title = title
571    self.title_exact = title_exact
572    self.opened_min = opened_min
573    self.opened_max = opened_max
574    self.edited_min = edited_min
575    self.edited_max = edited_max
576    self.owner = owner
577    self.writer = writer
578    self.reader = reader
579    self.show_folders = show_folders
580    self.show_deleted = show_deleted
581    self.ocr = ocr
582    self.target_language = target_language
583    self.source_language = source_language
584
585  def modify_request(self, http_request):
586    gdata.client._add_query_param('convert', self.convert, http_request)
587    gdata.client._add_query_param('title', self.title, http_request)
588    gdata.client._add_query_param('title-exact', self.title_exact,
589                                  http_request)
590    gdata.client._add_query_param('opened-min', self.opened_min, http_request)
591    gdata.client._add_query_param('opened-max', self.opened_max, http_request)
592    gdata.client._add_query_param('edited-min', self.edited_min, http_request)
593    gdata.client._add_query_param('edited-max', self.edited_max, http_request)
594    gdata.client._add_query_param('owner', self.owner, http_request)
595    gdata.client._add_query_param('writer', self.writer, http_request)
596    gdata.client._add_query_param('reader', self.reader, http_request)
597    gdata.client._add_query_param('showfolders', self.show_folders,
598                                  http_request)
599    gdata.client._add_query_param('showdeleted', self.show_deleted,
600                                  http_request)
601    gdata.client._add_query_param('ocr', self.ocr, http_request)
602    gdata.client._add_query_param('targetLanguage', self.target_language,
603                                  http_request)
604    gdata.client._add_query_param('sourceLanguage', self.source_language,
605                                  http_request)
606    gdata.client.Query.modify_request(self, http_request)
607
608  ModifyRequest = modify_request