forked from google/gdata-python-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.py
More file actions
executable file
·1093 lines (884 loc) · 40.9 KB
/
client.py
File metadata and controls
executable file
·1093 lines (884 loc) · 40.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/python
#
# Copyright 2011 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""DocsClient simplifies interactions with the Documents List API."""
__author__ = 'vicfryzel@google.com (Vic Fryzel)'
import copy
import mimetypes
import re
import urllib
import atom.data
import atom.http_core
import gdata.client
import gdata.docs.data
import gdata.gauth
# Feed URIs that are given by the API, but cannot be obtained without
# making a mostly unnecessary HTTP request.
RESOURCE_FEED_URI = '/feeds/default/private/full'
RESOURCE_SELF_LINK_TEMPLATE = RESOURCE_FEED_URI + '/%s'
RESOURCE_UPLOAD_URI = '/feeds/upload/create-session/default/private/full'
ARCHIVE_FEED_URI = '/feeds/default/private/archive'
METADATA_URI = '/feeds/metadata/default'
CHANGE_FEED_URI = '/feeds/default/private/changes'
class DocsClient(gdata.client.GDClient):
"""Client for all features of the Google Documents List API."""
host = 'docs.google.com'
api_version = '3.0'
auth_service = 'writely'
alt_auth_service = 'wise'
alt_auth_token = None
auth_scopes = gdata.gauth.AUTH_SCOPES['writely']
ssl = True
def request(self, method=None, uri=None, **kwargs):
"""Add support for imitating other users via 2-Legged OAuth.
Args:
uri: (optional) URI of the request in which to replace default with
self.xoauth_requestor_id.
Returns:
Result of super(DocsClient, self).request().
"""
if self.xoauth_requestor_id is not None and uri is not None:
if isinstance(uri, (str, unicode)):
uri = atom.http_core.Uri.parse_uri(uri)
uri.path.replace('/default', '/%s' % self.xoauth_requestor_id)
return super(DocsClient, self).request(method=method, uri=uri, **kwargs)
Request = request
def get_metadata(self, **kwargs):
"""Retrieves the metadata of a user account.
Args:
kwargs: Other parameters to pass to self.get_entry().
Returns:
gdata.docs.data.Metadata representing metadata of user's account.
"""
return self.get_entry(
METADATA_URI, desired_class=gdata.docs.data.Metadata, **kwargs)
GetMetadata = get_metadata
def get_changes(self, changestamp=None, max_results=None, show_root=None,
**kwargs):
"""Retrieves changes to a user's documents list.
Args:
changestamp: (optional) String changestamp value to query since.
If provided, returned changes will have a changestamp larger than
the given one.
max_results: (optional) Number of results to fetch. API will limit
this number to 100 at most.
show_root: (optional) True to include indications if a resource is in
the root collection.
kwargs: Other parameters to pass to self.get_feed().
Returns:
gdata.docs.data.ChangeFeed.
"""
uri = atom.http_core.Uri.parse_uri(CHANGE_FEED_URI)
if changestamp is not None:
uri.query['start-index'] = changestamp
if max_results is not None:
uri.query['max-results'] = max_results
if show_root is not None:
uri.query['showroot'] = str(show_root).lower()
return self.get_feed(
uri, desired_class=gdata.docs.data.ChangeFeed, **kwargs)
GetChanges = get_changes
def get_resources(self, uri=None, limit=None, show_root=None, **kwargs):
"""Retrieves the resources in a user's docslist, or the given URI.
Args:
uri: (optional) URI to query for resources. If None, then
gdata.docs.client.DocsClient.RESOURCE_FEED_URI is used, which will
query for all non-collections.
limit: int (optional) A maximum cap for the number of results to
return in the feed. By default, the API returns a maximum of 100
per page. Thus, if you set limit=5000, you will get <= 5000
documents (guarenteed no more than 5000), and will need to follow the
feed's next links (feed.GetNextLink()) to the rest. See
get_everything(). Similarly, if you set limit=50, only <= 50
documents are returned. Note: if the max-results parameter is set in
the uri parameter, it is chosen over a value set for limit.
show_root: (optional) True to include indications if a resource is in
the root collection.
kwargs: Other parameters to pass to self.get_feed().
Returns:
gdata.docs.data.ResourceFeed feed.
"""
if uri is None:
uri = RESOURCE_FEED_URI
if isinstance(uri, basestring):
uri = atom.http_core.Uri.parse_uri(uri)
# Add max-results param if it wasn't included in the uri.
if limit is not None and not 'max-results' in uri.query:
uri.query['max-results'] = limit
if show_root is not None:
uri.query['showroot'] = str(show_root).lower()
return self.get_feed(uri, desired_class=gdata.docs.data.ResourceFeed,
**kwargs)
GetResources = get_resources
def get_all_resources(self, uri=None, show_root=None, **kwargs):
"""Retrieves all of a user's non-collections or everything at the given URI.
Folders are not included in this by default. Pass in a custom URI to
include collections in your query. The DocsQuery class is an easy way to
generate such a URI.
This method makes multiple HTTP requests (by following the feed's next
links) in order to fetch the user's entire document list.
Args:
uri: (optional) URI to query the doclist feed with. If None, then use
DocsClient.RESOURCE_FEED_URI, which will retrieve all
non-collections.
show_root: (optional) True to include indications if a resource is in
the root collection.
kwargs: Other parameters to pass to self.GetResources().
Returns:
List of gdata.docs.data.Resource objects representing the retrieved
entries.
"""
if uri is None:
uri = RESOURCE_FEED_URI
if isinstance(uri, basestring):
uri = atom.http_core.Uri.parse_uri(uri)
if show_root is not None:
uri.query['showroot'] = str(show_root).lower()
feed = self.GetResources(uri=uri, **kwargs)
entries = feed.entry
while feed.GetNextLink() is not None:
feed = self.GetResources(feed.GetNextLink().href, **kwargs)
entries.extend(feed.entry)
return entries
GetAllResources = get_all_resources
def get_resource(self, entry, **kwargs):
"""Retrieves a resource again given its entry.
Args:
entry: gdata.docs.data.Resource to fetch and return.
kwargs: Other args to pass to GetResourceBySelfLink().
Returns:
gdata.docs.data.Resource representing retrieved resource.
"""
return self.GetResourceBySelfLink(entry.GetSelfLink().href, **kwargs)
GetResource = get_resource
def get_resource_by_id(self, resource_id, **kwargs):
"""Retrieves a resource again given its resource ID.
Args:
resource_id: Typed or untyped resource ID of a resource.
kwargs: Other args to pass to GetResourceBySelfLink().
Returns:
gdata.docs.data.Resource representing retrieved resource.
"""
return self.GetResourceBySelfLink(
RESOURCE_SELF_LINK_TEMPLATE % resource_id, **kwargs)
GetResourceById = get_resource_by_id
def get_resource_by_self_link(self, uri, etag=None, show_root=None,
**kwargs):
"""Retrieves a particular resource by its self link.
Args:
uri: str URI at which to query for given resource. This can be found
using entry.GetSelfLink().
etag: str (optional) The document/item's etag value to be used in a
conditional GET. See http://code.google.com/apis/documents/docs/3.0/
developers_guide_protocol.html#RetrievingCached.
show_root: (optional) True to include indications if a resource is in
the root collection.
kwargs: Other parameters to pass to self.get_entry().
Returns:
gdata.docs.data.Resource representing the retrieved resource.
"""
if isinstance(uri, basestring):
uri = atom.http_core.Uri.parse_uri(uri)
if show_root is not None:
uri.query['showroot'] = str(show_root).lower()
return self.get_entry(
uri , etag=etag, desired_class=gdata.docs.data.Resource, **kwargs)
GetResourceBySelfLink = get_resource_by_self_link
def get_resource_acl(self, entry, **kwargs):
"""Retrieves the ACL sharing permissions for the given entry.
Args:
entry: gdata.docs.data.Resource for which to get ACL.
kwargs: Other parameters to pass to self.get_feed().
Returns:
gdata.docs.data.AclFeed representing the resource's ACL.
"""
self._check_entry_is_resource(entry)
return self.get_feed(entry.GetAclFeedLink().href,
desired_class=gdata.docs.data.AclFeed, **kwargs)
GetResourceAcl = get_resource_acl
def create_resource(self, entry, media=None, collection=None,
create_uri=None, **kwargs):
"""Creates new entries in Google Docs, and uploads their contents.
Args:
entry: gdata.docs.data.Resource representing initial version
of entry being created. If media is also provided, the entry will
first be created with the given metadata and content.
media: (optional) gdata.data.MediaSource containing the file to be
uploaded.
collection: (optional) gdata.docs.data.Resource representing a collection
in which this new entry should be created. If provided along
with create_uri, create_uri will win (e.g. entry will be created at
create_uri, not necessarily in given collection).
create_uri: (optional) String URI at which to create the given entry. If
collection, media and create_uri are None, use
gdata.docs.client.RESOURCE_FEED_URI. If collection and create_uri are
None, use gdata.docs.client.RESOURCE_UPLOAD_URI. If collection and
media are not None,
collection.GetResumableCreateMediaLink() is used,
with the collection's resource ID substituted in.
kwargs: Other parameters to pass to self.post() and self.update().
Returns:
gdata.docs.data.Resource containing information about new entry.
"""
if media is not None:
if create_uri is None and collection is not None:
create_uri = collection.GetResumableCreateMediaLink().href
elif create_uri is None:
create_uri = RESOURCE_UPLOAD_URI
uploader = gdata.client.ResumableUploader(
self, media.file_handle, media.content_type, media.content_length,
desired_class=gdata.docs.data.Resource)
return uploader.upload_file(create_uri, entry, **kwargs)
else:
if create_uri is None and collection is not None:
create_uri = collection.content.src
elif create_uri is None:
create_uri = RESOURCE_FEED_URI
return self.post(
entry, create_uri, desired_class=gdata.docs.data.Resource, **kwargs)
CreateResource = create_resource
def update_resource(self, entry, media=None, update_metadata=True,
new_revision=False, **kwargs):
"""Updates an entry in Google Docs with new metadata and/or new data.
Args:
entry: Entry to update. Make any metadata changes to this entry.
media: (optional) gdata.data.MediaSource object containing the file with
which to replace the entry's data.
update_metadata: (optional) True to update the metadata from the entry
itself. You might set this to False to only update an entry's
file content, and not its metadata.
new_revision: (optional) True to create a new revision with this update,
False otherwise.
kwargs: Other parameters to pass to self.post().
Returns:
gdata.docs.data.Resource representing the updated entry.
"""
uri_params = {}
if new_revision:
uri_params['new-revision'] = 'true'
if update_metadata and media is None:
uri = atom.http_core.parse_uri(entry.GetEditLink().href)
uri.query.update(uri_params)
return super(DocsClient, self).update(entry, **kwargs)
else:
uploader = gdata.client.ResumableUploader(
self, media.file_handle, media.content_type, media.content_length,
desired_class=gdata.docs.data.Resource)
return uploader.UpdateFile(entry_or_resumable_edit_link=entry,
update_metadata=update_metadata,
uri_params=uri_params, **kwargs)
UpdateResource = update_resource
def download_resource(self, entry, file_path, extra_params=None, **kwargs):
"""Downloads the contents of the given entry to disk.
Note: to download a file in memory, use the DownloadResourceToMemory()
method.
Args:
entry: gdata.docs.data.Resource whose contents to fetch.
file_path: str Full path to which to save file.
extra_params: dict (optional) A map of any further parameters to control
how the document is downloaded/exported. For example, exporting a
spreadsheet as a .csv: extra_params={'gid': 0, 'exportFormat': 'csv'}
kwargs: Other parameters to pass to self._download_file().
Raises:
gdata.client.RequestError if the download URL is malformed or the server's
response was not successful.
"""
self._check_entry_is_not_collection(entry)
self._check_entry_has_content(entry)
uri = self._get_download_uri(entry.content.src, extra_params)
self._download_file(uri, file_path, **kwargs)
DownloadResource = download_resource
def download_resource_to_memory(self, entry, extra_params=None, **kwargs):
"""Returns the contents of the given entry.
Args:
entry: gdata.docs.data.Resource whose contents to fetch.
extra_params: dict (optional) A map of any further parameters to control
how the document is downloaded/exported. For example, exporting a
spreadsheet as a .csv: extra_params={'gid': 0, 'exportFormat': 'csv'}
kwargs: Other parameters to pass to self._get_content().
Returns:
Content of given resource after being downloaded.
Raises:
gdata.client.RequestError if the download URL is malformed or the server's
response was not successful.
"""
self._check_entry_is_not_collection(entry)
self._check_entry_has_content(entry)
uri = self._get_download_uri(entry.content.src, extra_params)
return self._get_content(uri, **kwargs)
DownloadResourceToMemory = download_resource_to_memory
def _get_download_uri(self, base_uri, extra_params=None):
uri = base_uri.replace('&', '&')
if extra_params is not None:
if 'exportFormat' in extra_params and '/Export?' not in uri and '/export?' not in uri:
raise gdata.client.Error, ('This entry type cannot be exported '
'as a different format.')
if 'gid' in extra_params and uri.find('spreadsheets') == -1:
raise gdata.client.Error, 'gid param is not valid for this resource type.'
uri += '&' + urllib.urlencode(extra_params)
return uri
def _get_content(self, uri, extra_params=None, auth_token=None, **kwargs):
"""Fetches the given resource's content.
This method is useful for downloading/exporting a file within enviornments
like Google App Engine, where the user may not have the ability to write
the file to a local disk.
Be warned, this method will use as much memory as needed to store the
fetched content. This could cause issues in your environment or app. This
is only different from Download() in that you will probably retain an
open reference to the data returned from this method, where as the data
from Download() will be immediately written to disk and the memory
freed. This client library currently doesn't support reading server
responses into a buffer or yielding an open file pointer to responses.
Args:
entry: Resource to fetch.
extra_params: dict (optional) A map of any further parameters to control
how the document is downloaded/exported. For example, exporting a
spreadsheet as a .csv: extra_params={'gid': 0, 'exportFormat': 'csv'}
auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
OAuthToken which authorizes this client to edit the user's data.
kwargs: Other parameters to pass to self.request().
Returns:
The binary file content.
Raises:
gdata.client.RequestError: on error response from server.
"""
server_response = None
token = auth_token
if 'spreadsheets' in uri and token is None \
and self.alt_auth_token is not None:
token = self.alt_auth_token
server_response = self.request(
'GET', uri, auth_token=token, **kwargs)
if server_response.status != 200:
raise gdata.client.RequestError, {'status': server_response.status,
'reason': server_response.reason,
'body': server_response.read()}
return server_response.read()
def _download_file(self, uri, file_path, **kwargs):
"""Downloads a file to disk from the specified URI.
Note: to download a file in memory, use the GetContent() method.
Args:
uri: str The full URL to download the file from.
file_path: str The full path to save the file to.
kwargs: Other parameters to pass to self.get_content().
Raises:
gdata.client.RequestError: on error response from server.
"""
f = open(file_path, 'wb')
try:
f.write(self._get_content(uri, **kwargs))
except gdata.client.RequestError, e:
f.close()
raise e
f.flush()
f.close()
_DownloadFile = _download_file
def copy_resource(self, entry, title, **kwargs):
"""Copies the given entry to a new entry with the given title.
Note: Files do not support this feature.
Args:
entry: gdata.docs.data.Resource to copy.
title: String title for the new entry.
kwargs: Other parameters to pass to self.post().
Returns:
gdata.docs.data.Resource representing duplicated resource.
"""
self._check_entry_is_resource(entry)
new_entry = gdata.docs.data.Resource(
title=atom.data.Title(text=title),
id=atom.data.Id(text=entry.GetSelfLink().href))
return self.post(new_entry, RESOURCE_FEED_URI, **kwargs)
CopyResource = copy_resource
def move_resource(self, entry, collection=None, keep_in_collections=False,
**kwargs):
"""Moves an item into a different collection (or out of all collections).
Args:
entry: gdata.docs.data.Resource to move.
collection: gdata.docs.data.Resource (optional) An object representing
the destination collection. If None, set keep_in_collections to
False to remove the item from all collections.
keep_in_collections: boolean (optional) If True, the given entry
is not removed from any existing collections it is already in.
kwargs: Other parameters to pass to self.post().
Returns:
gdata.docs.data.Resource of the moved entry.
"""
self._check_entry_is_resource(entry)
# Remove the item from any collections it is already in.
if not keep_in_collections:
for current_collection in entry.InCollections():
uri = '%s/contents/%s' % (
current_collection.href,
urllib.quote(entry.resource_id.text))
self.delete(uri, force=True)
if collection is not None:
self._check_entry_is_collection(collection)
entry = self.post(entry, collection.content.src, **kwargs)
return entry
MoveResource = move_resource
def delete_resource(self, entry, permanent=False, **kwargs):
"""Trashes or deletes the given entry.
Args:
entry: gdata.docs.data.Resource to trash or delete.
permanent: True to skip the trash and delete the entry forever.
kwargs: Other args to pass to gdata.client.GDClient.Delete()
Returns:
Result of delete request.
"""
if permanent:
kwargs['delete'] = 'true'
return gdata.client.GDClient.delete(self, entry, **kwargs)
DeleteResource = delete_resource
def _check_entry_is_resource(self, entry):
"""Ensures given entry is a gdata.docs.data.Resource.
Args:
entry: Entry to test.
Raises:
ValueError: If given entry is not a resource.
"""
if not isinstance(entry, gdata.docs.data.Resource):
raise ValueError('%s is not a gdata.docs.data.Resource' % str(entry))
def _check_entry_is_collection(self, entry):
"""Ensures given entry is a collection.
Args:
entry: Entry to test.
Raises:
ValueError: If given entry is a collection.
"""
self._check_entry_is_resource(entry)
if entry.get_resource_type() != gdata.docs.data.COLLECTION_LABEL:
raise ValueError('%s is not a collection' % str(entry))
def _check_entry_is_not_collection(self, entry):
"""Ensures given entry is not a collection.
Args:
entry: Entry to test.
Raises:
ValueError: If given entry is a collection.
"""
try:
self._check_entry_is_resource(entry)
except ValueError:
return
if entry.get_resource_type() == gdata.docs.data.COLLECTION_LABEL:
raise ValueError(
'%s is a collection, which is not valid in this method' % str(entry))
def _check_entry_has_content(self, entry):
"""Ensures given entry has a content element with src.
Args:
entry: Entry to test.
Raises:
ValueError: If given entry is not an entry or has no content src.
"""
# Don't use _check_entry_is_resource since could be Revision etc
if not (hasattr(entry, 'content') and entry.content and
entry.content.src):
raise ValueError('Entry %s has no downloadable content.' % entry)
def get_acl(self, entry, **kwargs):
"""Retrieves an AclFeed for the given resource.
Args:
entry: gdata.docs.data.Resource to fetch AclFeed for.
kwargs: Other args to pass to GetFeed().
Returns:
gdata.docs.data.AclFeed representing retrieved entries.
"""
self._check_entry_is_resource(entry)
return self.get_feed(
entry.GetAclFeedLink().href,
desired_class=gdata.docs.data.AclFeed, **kwargs)
GetAcl = get_acl
def get_acl_entry(self, entry, **kwargs):
"""Retrieves an AclEntry again.
This is useful if you need to poll for an ACL changing.
Args:
entry: gdata.docs.data.AclEntry to fetch and return.
kwargs: Other args to pass to GetAclEntryBySelfLink().
Returns:
gdata.docs.data.AclEntry representing retrieved entry.
"""
return self.GetAclEntryBySelfLink(entry.GetSelfLink().href, **kwargs)
GetAclEntry = get_acl_entry
def get_acl_entry_by_self_link(self, self_link, **kwargs):
"""Retrieves a particular AclEntry by its self link.
Args:
self_link: URI at which to query for given ACL entry. This can be found
using entry.GetSelfLink().
kwargs: Other parameters to pass to self.get_entry().
Returns:
gdata.docs.data.AclEntry representing the retrieved entry.
"""
if isinstance(self_link, atom.data.Link):
self_link = self_link.href
return self.get_entry(self_link, desired_class=gdata.docs.data.AclEntry,
**kwargs)
GetAclEntryBySelfLink = get_acl_entry_by_self_link
def add_acl_entry(self, resource, acl_entry, send_notifications=None,
**kwargs):
"""Adds the given AclEntry to the given Resource.
Args:
resource: gdata.docs.data.Resource to which to add AclEntry.
acl_entry: gdata.docs.data.AclEntry representing ACL entry to add.
send_notifications: True if users should be notified by email when
this AclEntry is added.
kwargs: Other parameters to pass to self.post().
Returns:
gdata.docs.data.AclEntry containing information about new entry.
Raises:
ValueError: If given resource has no ACL link.
"""
uri = resource.GetAclLink().href
if uri is None:
raise ValueError(('Given resource has no ACL link. Did you fetch this'
'resource from the API?'))
if send_notifications is not None:
if not send_notifications:
uri += '?send-notification-emails=false'
return self.post(acl_entry, uri, desired_class=gdata.docs.data.AclEntry,
**kwargs)
AddAclEntry = add_acl_entry
def update_acl_entry(self, entry, send_notifications=None, **kwargs):
"""Updates the given AclEntry with new metadata.
Args:
entry: AclEntry to update. Make any metadata changes to this entry.
send_notifications: True if users should be notified by email when
this AclEntry is updated.
kwargs: Other parameters to pass to super(DocsClient, self).update().
Returns:
gdata.docs.data.AclEntry representing the updated ACL entry.
"""
uri = entry.GetEditLink().href
if not send_notifications:
uri += '?send-notification-emails=false'
return super(DocsClient, self).update(entry, uri=uri, **kwargs)
UpdateAclEntry = update_acl_entry
def delete_acl_entry(self, entry, **kwargs):
"""Deletes the given AclEntry.
Args:
entry: gdata.docs.data.AclEntry to delete.
kwargs: Other args to pass to gdata.client.GDClient.Delete()
Returns:
Result of delete request.
"""
return super(DocsClient, self).delete(entry.GetEditLink().href,
**kwargs)
DeleteAclEntry = delete_acl_entry
def batch_process_acl_entries(self, resource, entries, **kwargs):
"""Applies the specified operation of each entry in a single request.
To use this, simply set acl_entry.batch_operation to one of
['query', 'insert', 'update', 'delete'], and optionally set
acl_entry.batch_id to a string of your choice.
Then, put all of your modified AclEntry objects into a list and pass
that list as the entries parameter.
Args:
resource: gdata.docs.data.Resource to which the given entries belong.
entries: [gdata.docs.data.AclEntry] to modify in some way.
kwargs: Other args to pass to gdata.client.GDClient.post()
Returns:
Resulting gdata.docs.data.AclFeed of changes.
"""
feed = gdata.docs.data.AclFeed()
feed.entry = entries
return super(DocsClient, self).post(
feed, uri=resource.GetAclLink().href + '/batch', **kwargs)
BatchProcessAclEntries = batch_process_acl_entries
def get_revisions(self, entry, **kwargs):
"""Retrieves the revision history for a resource.
Args:
entry: gdata.docs.data.Resource for which to get revisions.
kwargs: Other parameters to pass to self.get_feed().
Returns:
gdata.docs.data.RevisionFeed representing the resource's revisions.
"""
self._check_entry_is_resource(entry)
return self.get_feed(
entry.GetRevisionsFeedLink().href,
desired_class=gdata.docs.data.RevisionFeed, **kwargs)
GetRevisions = get_revisions
def get_revision(self, entry, **kwargs):
"""Retrieves a revision again given its entry.
Args:
entry: gdata.docs.data.Revision to fetch and return.
kwargs: Other args to pass to GetRevisionBySelfLink().
Returns:
gdata.docs.data.Revision representing retrieved revision.
"""
return self.GetRevisionBySelfLink(entry.GetSelfLink().href, **kwargs)
GetRevision = get_revision
def get_revision_by_self_link(self, self_link, **kwargs):
"""Retrieves a particular reivision by its self link.
Args:
self_link: URI at which to query for given revision. This can be found
using entry.GetSelfLink().
kwargs: Other parameters to pass to self.get_entry().
Returns:
gdata.docs.data.Revision representing the retrieved revision.
"""
if isinstance(self_link, atom.data.Link):
self_link = self_link.href
return self.get_entry(self_link, desired_class=gdata.docs.data.Revision,
**kwargs)
GetRevisionBySelfLink = get_revision_by_self_link
def download_revision(self, entry, file_path, extra_params=None, **kwargs):
"""Downloads the contents of the given revision to disk.
Note: to download a revision in memory, use the DownloadRevisionToMemory()
method.
Args:
entry: gdata.docs.data.Revision whose contents to fetch.
file_path: str Full path to which to save file.
extra_params: dict (optional) A map of any further parameters to control
how the document is downloaded.
kwargs: Other parameters to pass to self._download_file().
Raises:
gdata.client.RequestError if the download URL is malformed or the server's
response was not successful.
"""
self._check_entry_is_not_collection(entry)
self._check_entry_has_content(entry)
uri = self._get_download_uri(entry.content.src, extra_params)
self._download_file(uri, file_path, **kwargs)
DownloadRevision = download_revision
def download_revision_to_memory(self, entry, extra_params=None, **kwargs):
"""Returns the contents of the given revision.
Args:
entry: gdata.docs.data.Revision whose contents to fetch.
extra_params: dict (optional) A map of any further parameters to control
how the document is downloaded/exported.
kwargs: Other parameters to pass to self._get_content().
Returns:
Content of given revision after being downloaded.
Raises:
gdata.client.RequestError if the download URL is malformed or the server's
response was not successful.
"""
self._check_entry_is_not_collection(entry)
self._check_entry_has_content(entry)
uri = self._get_download_uri(entry.content.src, extra_params)
return self._get_content(uri, **kwargs)
DownloadRevisionToMemory = download_revision_to_memory
def publish_revision(self, entry, publish_auto=None,
publish_outside_domain=False, **kwargs):
"""Publishes the given revision.
This method can only be used for document revisions.
Args:
entry: Revision to update.
publish_auto: True to automatically publish future revisions of the
document. False to not automatically publish future revisions.
None to take no action and use the default value.
publish_outside_domain: True to make the published revision available
outside of a Google Apps domain. False to not publish outside
the domain. None to use the default value.
kwargs: Other parameters to pass to super(DocsClient, self).update().
Returns:
gdata.docs.data.Revision representing the updated revision.
"""
entry.publish = gdata.docs.data.Publish(value='true')
if publish_auto == True:
entry.publish_auto = gdata.docs.data.PublishAuto(value='true')
elif publish_auto == False:
entry.publish_auto = gdata.docs.data.PublishAuto(value='false')
if publish_outside_domain == True:
entry.publish_outside_domain = \
gdata.docs.data.PublishOutsideDomain(value='true')
elif publish_outside_domain == False:
entry.publish_outside_domain = \
gdata.docs.data.PublishOutsideDomain(value='false')
return super(DocsClient, self).update(entry, force=True, **kwargs)
PublishRevision = publish_revision
def unpublish_revision(self, entry, **kwargs):
"""Unpublishes the given revision.
This method can only be used for document revisions.
Args:
entry: Revision to update.
kwargs: Other parameters to pass to super(DocsClient, self).update().
Returns:
gdata.docs.data.Revision representing the updated revision.
"""
entry.publish = gdata.docs.data.Publish(value='false')
return super(DocsClient, self).update(entry, force=True, **kwargs)
UnpublishRevision = unpublish_revision
def delete_revision(self, entry, **kwargs):
"""Deletes the given Revision.
Args:
entry: gdata.docs.data.Revision to delete.
kwargs: Other args to pass to gdata.client.GDClient.Delete()
Returns:
Result of delete request.
"""
return super(DocsClient, self).delete(entry, force=True, **kwargs)
DeleteRevision = delete_revision
def get_archive(self, entry, **kwargs):
"""Retrieves an archive again given its entry.
This is useful if you need to poll for an archive completing.
Args:
entry: gdata.docs.data.Archive to fetch and return.
kwargs: Other args to pass to GetArchiveBySelfLink().
Returns:
gdata.docs.data.Archive representing retrieved archive.
"""
return self.GetArchiveBySelfLink(entry.GetSelfLink().href, **kwargs)
GetArchive = get_archive
def get_archive_by_self_link(self, self_link, **kwargs):
"""Retrieves a particular archive by its self link.
Args:
self_link: URI at which to query for given archive. This can be found
using entry.GetSelfLink().
kwargs: Other parameters to pass to self.get_entry().
Returns:
gdata.docs.data.Archive representing the retrieved archive.
"""
if isinstance(self_link, atom.data.Link):
self_link = self_link.href
return self.get_entry(self_link, desired_class=gdata.docs.data.Archive,
**kwargs)
GetArchiveBySelfLink = get_archive_by_self_link
def create_archive(self, entry, **kwargs):
"""Creates a new archive of resources.
Args:
entry: gdata.docs.data.Archive representing metadata of archive to
create.
kwargs: Other parameters to pass to self.post().
Returns:
gdata.docs.data.Archive containing information about new archive.
"""
return self.post(entry, ARCHIVE_FEED_URI,
desired_class=gdata.docs.data.Archive, **kwargs)
CreateArchive = create_archive
def update_archive(self, entry, **kwargs):
"""Updates the given Archive with new metadata.
This method is really only useful for updating the notification email
address of an archive that is being processed.
Args:
entry: Archive to update. Make any metadata changes to this entry.
kwargs: Other parameters to pass to super(DocsClient, self).update().
Returns:
gdata.docs.data.Archive representing the updated archive.
"""
return super(DocsClient, self).update(entry, **kwargs)
UpdateArchive = update_archive
download_archive = DownloadResource
DownloadArchive = download_archive
download_archive_to_memory = DownloadResourceToMemory
DownloadArchiveToMemory = download_archive_to_memory
def delete_archive(self, entry, **kwargs):
"""Aborts the given Archive operation, or deletes the Archive.
Args:
entry: gdata.docs.data.Archive to delete.
kwargs: Other args to pass to gdata.client.GDClient.Delete()
Returns:
Result of delete request.
"""
return super(DocsClient, self).delete(entry, force=True, **kwargs)
DeleteArchive = delete_archive
class DocsQuery(gdata.client.Query):
def __init__(self, title=None, title_exact=None, opened_min=None,
opened_max=None, edited_min=None, edited_max=None, owner=None,
writer=None, reader=None, show_collections=None, show_root=None,
show_deleted=None, ocr=None, target_language=None,
source_language=None, convert=None, query=None, **kwargs):
"""Constructs a query URL for the Google Documents List API.
Args:
title: str (optional) Specifies the search terms for the title of a
document. This parameter used without title_exact will only
submit partial queries, not exact queries.