Revision 3dabe5d2 kamaki/clients/pithos_rest_api.py

b/kamaki/clients/pithos_rest_api.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from kamaki.clients.storage import StorageClient, ClientError
34
from kamaki.clients.storage import StorageClient
35 35
from kamaki.clients.utils import path4url, list2str
36 36

  
37

  
37 38
class PithosRestAPI(StorageClient):
38 39

  
39
    def account_head(self, until = None,
40
        if_modified_since=None, if_unmodified_since=None, *args, **kwargs):
40
    def account_head(self,
41
        until=None,
42
        if_modified_since=None,
43
        if_unmodified_since=None,
44
        *args,
45
        **kwargs):
41 46
        """ Full Pithos+ HEAD at account level
42 47
        --- request parameters ---
43 48
        @param until (string): optional timestamp
44 49
        --- --- optional request headers ---
45
        @param if_modified_since (string): Retrieve if account has changed since provided timestamp
46
        @param if_unmodified_since (string): Retrieve if account has not changed since provided timestamp
50
        @param if_modified_since (string): Retrieve if account has changed
51
            since provided timestamp
52
        @param if_unmodified_since (string): Retrieve if account has not
53
            change since provided timestamp
47 54
        """
48 55
        self.assert_account()
49 56
        path = path4url(self.account)
50 57

  
51
        self.set_param('until', until, iff = until is not None)
58
        self.set_param('until', until, iff=until is not None)
52 59
        self.set_header('If-Modified-Since', if_modified_since)
53 60
        self.set_header('If-Unmodified-Since', if_unmodified_since)
54 61

  
55 62
        success = kwargs.pop('success', 204)
56 63
        return self.head(path, *args, success=success, **kwargs)
57 64

  
58
    def account_get(self, limit=None, marker=None, format='json', show_only_shared=False, until=None,
59
        if_modified_since=None, if_unmodified_since=None, *args, **kwargs):
65
    def account_get(self,
66
        limit=None,
67
        marker=None,
68
        format='json',
69
        show_only_shared=False,
70
        until=None,
71
        if_modified_since=None,
72
        if_unmodified_since=None,
73
        *args,
74
        **kwargs):
60 75
        """  Full Pithos+ GET at account level
61 76
        --- request parameters ---
62
        @param limit (integer): The amount of results requested (server will use default value if None)
63
        @param marker (string): Return containers with name lexicographically after marker
64
        @param format (string): reply format can be json or xml (default: json)
65
        @param shared (bool): If true, only shared containers will be included in results
77
        @param limit (integer): The amount of results requested
78
            (server will use default value if None)
79
        @param marker (string): Return containers with name
80
            lexicographically after marker
81
        @param format (string): reply format can be json or xml
82
            (default: json)
83
        @param shared (bool): If true, only shared containers will be
84
            included in results
66 85
        @param until (string): optional timestamp
67 86
        --- --- optional request headers ---
68
        @param if_modified_since (string): Retrieve if account has changed since provided timestamp
69
        @param if_unmodified_since (string): Retrieve if account has not changed since provided timestamp
87
        @param if_modified_since (string): Retrieve if account has changed
88
            since provided timestamp
89
        @param if_unmodified_since (string): Retrieve if account has not
90
            changed since provided timestamp
70 91
        """
71 92
        self.assert_account()
72 93

  
73
        self.set_param('format',format, iff = format is not None)
74
        self.set_param('limit',limit, iff = limit is not None)
75
        self.set_param('marker',marker, iff = marker is not None)
76
        self.set_param('shared', iff = show_only_shared)
77
        self.set_param('until',until, iff = until is not None)
94
        self.set_param('format', format, iff=format is not None)
95
        self.set_param('limit', limit, iff=limit is not None)
96
        self.set_param('marker', marker, iff=marker is not None)
97
        self.set_param('shared', iff=show_only_shared)
98
        self.set_param('until', until, iff=until is not None)
78 99

  
79 100
        self.set_header('If-Modified-Since', if_modified_since)
80 101
        self.set_header('If-Unmodified-Since', if_unmodified_since)
81 102

  
82 103
        path = path4url(self.account)
83 104
        success = kwargs.pop('success', (200, 204))
84
        return self.get(path, *args, success = success, **kwargs)
105
        return self.get(path, *args, success=success, **kwargs)
85 106

  
86
    def account_post(self, update=True,
87
        groups={}, metadata=None, quota=None, versioning=None, *args, **kwargs):
107
    def account_post(self,
108
        update=True,
109
        groups={},
110
        metadata=None,
111
        quota=None,
112
        versioning=None,
113
        *args,
114
        **kwargs):
88 115
        """ Full Pithos+ POST at account level
89 116
        --- request parameters ---
90 117
        @param update (bool): if True, Do not replace metadata/groups
91 118
        --- request headers ---
92 119
        @groups (dict): Optional user defined groups in the form
93
                    {   'group1':['user1', 'user2', ...], 
120
                    {   'group1':['user1', 'user2', ...],
94 121
                        'group2':['userA', 'userB', ...], ...
95 122
                    }
96 123
        @metadata (dict): Optional user defined metadata in the form
......
103 130
        """
104 131
        self.assert_account()
105 132

  
106
        self.set_param('update', iff = update)
133
        self.set_param('update', iff=update)
107 134

  
108 135
        for group, usernames in groups.items():
109 136
            userstr = ''
......
111 138
            for user in usernames:
112 139
                userstr = userstr + dlm + user
113 140
                dlm = ','
114
            self.set_header('X-Account-Group-'+group, userstr)
141
            self.set_header('X-Account-Group-' + group, userstr)
115 142
        if metadata is not None:
116 143
            for metaname, metaval in metadata.items():
117
                self.set_header('X-Account-Meta-'+metaname, metaval)
144
                self.set_header('X-Account-Meta-' + metaname, metaval)
118 145
        self.set_header('X-Account-Policy-Quota', quota)
119 146
        self.set_header('X-Account-Policy-Versioning', versioning)
120 147

  
......
127 154
        """ Full Pithos+ HEAD at container level
128 155
        --- request params ---
129 156
        @param until (string): optional timestamp
130
        --- optional request headers --- 
131
        @param if_modified_since (string): Retrieve if account has changed since provided timestamp
132
        @param if_unmodified_since (string): Retrieve if account has not changed since provided timestamp
157
        --- optional request headers ---
158
        @param if_modified_since (string): Retrieve if account has changed
159
            since provided timestamp
160
        @param if_unmodified_since (string): Retrieve if account has not
161
            changed since provided timestamp
133 162
        """
134 163
        self.assert_container()
135 164

  
......
142 171
        success = kwargs.pop('success', 204)
143 172
        return self.head(path, *args, success=success, **kwargs)
144 173

  
145
    def container_get(self, limit = None, marker = None, prefix=None, delimiter=None, path = None,
146
        format='json', meta=[], show_only_shared=False, until=None,
147
        if_modified_since=None, if_unmodified_since=None, *args, **kwargs):
174
    def container_get(self,
175
        limit=None,
176
        marker=None,
177
        prefix=None,
178
        delimiter=None,
179
        path=None,
180
        format='json',
181
        meta=[],
182
        show_only_shared=False,
183
        until=None,
184
        if_modified_since=None,
185
        if_unmodified_since=None,
186
        *args,
187
        **kwargs):
148 188
        """ Full Pithos+ GET at container level
149 189
        --- request parameters ---
150
        @param limit (integer): The amount of results requested (server qill use default value if None)
151
        @param marker (string): Return containers with name lexicographically after marker
190
        @param limit (integer): The amount of results requested
191
            (server qill use default value if None)
192
        @param marker (string): Return containers with name lexicographically
193
            after marker
152 194
        @param prefix (string): Return objects starting with prefix
153 195
        @param delimiter (string): Return objects up to the delimiter
154
        @param path (string): assume prefix = path and delimiter = / (overwrites prefix
155
        and delimiter)
156
        @param format (string): reply format can be json or xml (default: json)
157
        @param meta (list): Return objects that satisfy the key queries in the specified
158
        comma separated list (use <key>, !<key> for existence queries, <key><op><value>
159
        for value queries, where <op> can be one of =, !=, <=, >=, <, >)
160
        @param shared (bool): If true, only shared containers will be included in results
196
        @param path (string): assume prefix = path and delimiter = /
197
            (overwrites prefix and delimiter)
198
        @param format (string): reply format can be json or xml (default:json)
199
        @param meta (list): Return objects that satisfy the key queries in
200
            the specified comma separated list (use <key>, !<key> for
201
            existence queries, <key><op><value> for value queries, where <op>
202
            can be one of =, !=, <=, >=, <, >)
203
        @param shared (bool): If true, only shared containers will be included
204
        in results
161 205
        @param until (string): optional timestamp
162 206
        --- --- optional request headers ---
163
        @param if_modified_since (string): Retrieve if account has changed since provided timestamp
164
        @param if_unmodified_since (string): Retrieve if account has not changed since provided timestamp
207
        @param if_modified_since (string): Retrieve if account has changed
208
            since provided timestamp
209
        @param if_unmodified_since (string): Retrieve if account has not
210
            changed since provided timestamp
165 211
        """
166 212
        self.assert_container()
167 213

  
......
174 220
        else:
175 221
            self.set_param('path', path)
176 222
        self.set_param('shared', iff=show_only_shared)
177
        self.set_param('meta', list2str(meta), iff=meta is not None and len(meta) > 0)
223
        self.set_param('meta',
224
            list2str(meta),
225
            iff=meta is not None and len(meta) > 0)
178 226
        self.set_param('until', until, iff=until is not None)
179 227

  
180 228
        self.set_header('If-Modified-Since', if_modified_since)
......
184 232
        success = kwargs.pop('success', 200)
185 233
        return self.get(path, *args, success=success, **kwargs)
186 234

  
187
    def container_put(self, quota=None, versioning=None, metadata=None, *args, **kwargs):
235
    def container_put(self,
236
        quota=None,
237
        versioning=None,
238
        metadata=None,
239
        *args,
240
        **kwargs):
188 241
        """ Full Pithos+ PUT at container level
189 242
        --- request headers ---
190 243
        @param quota (integer): Size limit in KB
......
198 251

  
199 252
        if metadata is not None:
200 253
            for metaname, metaval in metadata.items():
201
                self.set_header('X-Container-Meta-'+metaname, metaval)
254
                self.set_header('X-Container-Meta-' + metaname, metaval)
202 255
        self.set_header('X-Container-Policy-Quota', quota)
203 256
        self.set_header('X-Container-Policy-Versioning', versioning)
204 257

  
205 258
        path = path4url(self.account, self.container)
206
        success = kwargs.pop('success',(201, 202))
259
        success = kwargs.pop('success', (201, 202))
207 260
        return self.put(path, *args, success=success, **kwargs)
208 261

  
209
    def container_post(self, update=True, format='json',
210
        quota=None, versioning=None, metadata=None, content_type=None, content_length=None,
211
        transfer_encoding=None, *args, **kwargs):
262
    def container_post(self,
263
        update=True,
264
        format='json',
265
        quota=None,
266
        versioning=None,
267
        metadata=None,
268
        content_type=None,
269
        content_length=None,
270
        transfer_encoding=None,
271
        *args,
272
        **kwargs):
212 273
        """ Full Pithos+ POST at container level
213 274
        --- request params ---
214 275
        @param update (bool):  if True, Do not replace metadata/groups
......
231 292

  
232 293
        if metadata is not None:
233 294
            for metaname, metaval in metadata.items():
234
                self.set_header('X-Container-Meta-'+metaname, metaval)
295
                self.set_header('X-Container-Meta-' + metaname, metaval)
235 296
        self.set_header('X-Container-Policy-Quota', quota)
236 297
        self.set_header('X-Container-Policy-Versioning', versioning)
237 298
        self.set_header('Content-Type', content_type)
......
245 306
    def container_delete(self, until=None, delimiter=None, *args, **kwargs):
246 307
        """ Full Pithos+ DELETE at container level
247 308
        --- request parameters ---
248
        @param until (timestamp string): if defined, container is purged up to that time
309
        @param until (timestamp string): if defined, container is purged up to
310
            that time
249 311
        """
250
        self.assert_container()        
312
        self.assert_container()
251 313

  
252 314
        self.set_param('until', until, iff=until is not None)
253 315
        self.set_param('delimiter', delimiter, iff=delimiter is not None)
254 316

  
255
        path=path4url(self.account, self.container)
317
        path = path4url(self.account, self.container)
256 318
        success = kwargs.pop('success', 204)
257 319
        return self.delete(path, success=success)
258 320

  
259
    def object_head(self, object, version=None, if_etag_match=None, if_etag_not_match = None,
260
        if_modified_since = None, if_unmodified_since = None, *args, **kwargs):
321
    def object_head(self, object,
322
        version=None,
323
        if_etag_match=None,
324
        if_etag_not_match=None,
325
        if_modified_since=None,
326
        if_unmodified_since=None,
327
        *args,
328
        **kwargs):
261 329
        """ Full Pithos+ HEAD at object level
262 330
        --- request parameters ---
263 331
        @param version (string): optional version identified
......
266 334
                with etag matching with this
267 335
        @param if_etag_not_match (string): if provided, return only results
268 336
                with etag not matching with this
269
        @param if_modified_since (string): Retrieve if account has changed since provided timestamp
270
        @param if_unmodified_since (string): Retrieve if account has not changed since provided timestamp
337
        @param if_modified_since (string): Retrieve if account has changed
338
            since provided timestamp
339
        @param if_unmodified_since (string): Retrieve if account has not
340
            changed since provided timestamp
271 341
        """
272 342
        self.assert_container()
273 343

  
......
278 348
        self.set_header('If-Modified-Since', if_modified_since)
279 349
        self.set_header('If-Unmodified-Since', if_unmodified_since)
280 350

  
281
        path=path4url(self.account, self.container, object)
351
        path = path4url(self.account, self.container, object)
282 352
        success = kwargs.pop('success', 200)
283 353
        return self.head(path, *args, success=success, **kwargs)
284 354

  
285
    def object_get(self, object, format='json', hashmap=False, version=None,
286
        data_range=None, if_range=False, if_etag_match=None, if_etag_not_match = None,
287
        if_modified_since = None, if_unmodified_since = None, *args, **kwargs):
355
    def object_get(self, object,
356
        format='json',
357
        hashmap=False,
358
        version=None,
359
        data_range=None,
360
        if_range=False,
361
        if_etag_match=None,
362
        if_etag_not_match=None,
363
        if_modified_since=None,
364
        if_unmodified_since=None,
365
        *args,
366
        **kwargs):
288 367
        """ Full Pithos+ GET at object level
289 368
        --- request parameters ---
290 369
        @param format (string): json (default) or xml
......
292 371
        @param version (string): optional version identified
293 372
        --- request headers ---
294 373
        @param data_range (string): Optional range of data to retrieve
295
        @param if_range (bool): 
374
        @param if_range (bool):
296 375
        @param if_etag_match (string): if provided, return only results
297 376
                with etag matching with this
298 377
        @param if_etag_not_match (string): if provided, return only results
299 378
                with etag not matching with this
300
        @param if_modified_since (string): Retrieve if account has changed since provided timestamp
301
        @param if_unmodified_since (string): Retrieve if account has not changed since provided timestamp
379
        @param if_modified_since (string): Retrieve if account has changed
380
            since provided timestamp
381
        @param if_unmodified_since (string): Retrieve if account has not
382
            changed since provided timestamp
302 383
        """
303 384
        self.assert_container()
304 385

  
......
307 388
        self.set_param('hashmap', hashmap, iff=hashmap)
308 389

  
309 390
        self.set_header('Range', data_range)
310
        self.set_header('If-Range', '', if_range is True and data_range is not None)
391
        self.set_header('If-Range', '',
392
            if_range is True and data_range is not None)
311 393
        self.set_header('If-Match', if_etag_match, )
312 394
        self.set_header('If-None-Match', if_etag_not_match)
313 395
        self.set_header('If-Modified-Since', if_modified_since)
314 396
        self.set_header('If-Unmodified-Since', if_unmodified_since)
315 397

  
316
        path=path4url(self.account, self.container, object)
398
        path = path4url(self.account, self.container, object)
317 399
        success = kwargs.pop('success', 200)
318 400
        return self.get(path, *args, success=success, **kwargs)
319 401

  
320
    def object_put(self, object, format='json', hashmap=False, delimiter = None, if_etag_match=None,
321
        if_etag_not_match = None, etag=None, content_length = None, content_type=None,
322
        transfer_encoding=None, copy_from=None, move_from=None, source_account=None,
323
        source_version=None, content_encoding = None, content_disposition=None, manifest = None,
324
        permitions =None, public = None, metadata=None, *args, **kwargs):
402
    def object_put(self, object,
403
        format='json',
404
        hashmap=False,
405
        delimiter=None,
406
        if_etag_match=None,
407
        if_etag_not_match=None,
408
        etag=None,
409
        content_length=None,
410
        content_type=None,
411
        transfer_encoding=None,
412
        copy_from=None,
413
        move_from=None,
414
        source_account=None,
415
        source_version=None,
416
        content_encoding=None,
417
        content_disposition=None,
418
        manifest=None,
419
        permissions=None,
420
        public=None,
421
        metadata=None,
422
        *args,
423
        **kwargs):
325 424
        """ Full Pithos+ PUT at object level
326 425
        --- request parameters ---
327 426
        @param format (string): json (default) or xml
......
331 430
                with etag matching with this
332 431
        @param if_etag_not_match (string): if provided, return only results
333 432
                with etag not matching with this
334
        @param etag (string): The MD5 hash of the object (optional to check written data)
433
        @param etag (string): The MD5 hash of the object (optional to check
434
            written data)
335 435
        @param content_length (integer): The size of the data written
336 436
        @param content_type (string): The MIME content type of the object
337
        @param transfer_encoding (string): Set to chunked to specify incremental uploading (if used, Content-Length is ignored)
338
        @param copy_from (string): The source path in the form /<container>/<object>
339
        @param move_from (string): The source path in the form /<container>/<object>
437
        @param transfer_encoding (string): Set to chunked to specify
438
            incremental uploading (if used, Content-Length is ignored)
439
        @param copy_from (string): The source path in the form
440
            /<container>/<object>
441
        @param move_from (string): The source path in the form
442
            /<container>/<object>
340 443
        @param source_account (string): The source account to copy/move from
341 444
        @param source_version (string): The source version to copy from
342 445
        @param conent_encoding (string): The encoding of the object
343
        @param content_disposition (string): The presentation style of the object
344
        @param manifest (string): Object parts prefix in /<container>/<object> form
345
        @param permitions (dict): Object permissions in the form (all fields are optional)
346
                {'read':[user1, group1, user2, ...], 'write':['user3, group2, group3, ...]}
347
        @param public (bool): If true, Object is publicly accessible, if false, not
446
        @param content_disposition (string): Presentation style of the object
447
        @param manifest (string): Object parts prefix in
448
            /<container>/<object> form
449
        @param permissions (dict): Object permissions in the form (all fields
450
            are optional)
451
            {   'read':[user1, group1, user2, ...],
452
                'write':['user3, group2, group3, ...]
453
            }
454
        @param public (bool): If true, Object is publicly accessible,
455
            if false, not
348 456
        @param metadata (dict): Optional user defined metadata in the form
349 457
                {'meta-key-1':'meta-value-1', 'meta-key-2':'meta-value-2', ...}
350 458
        """
......
368 476
        self.set_header('Content-Disposition', content_disposition)
369 477
        self.set_header('X-Object-Manifest', manifest)
370 478
        perms = None
371
        if permitions is not None:
372
            for permition_type, permition_list in permitions.items():
479
        if permissions:
480
            for permission_type, permission_list in permissions.items():
373 481
                if perms is None:
374
                    perms = '' #Remove permitions
375
                if len(permition_list) == 0:
482
                    perms = ''  # Remove permissions
483
                if len(permission_list) == 0:
376 484
                    continue
377
                perms += ';'+permition_type if len(perms) > 0 else permition_type
378
                perms += '='+list2str(permition_list, seperator=',')
485
                if len(perms):
486
                    perms += ';'
487
                perms += '%s=%s'\
488
                % (permission_type, list2str(permission_list, seperator=','))
379 489
        self.set_header('X-Object-Sharing', perms)
380 490
        self.set_header('X-Object-Public', public)
381 491
        if metadata is not None:
382 492
            for key, val in metadata.items():
383
                self.set_header('X-Object-Meta-'+key, val)
493
                self.set_header('X-Object-Meta-' + key, val)
384 494

  
385
        path=path4url(self.account, self.container, object)
495
        path = path4url(self.account, self.container, object)
386 496
        success = kwargs.pop('success', 201)
387 497
        return self.put(path, *args, success=success, **kwargs)
388 498

  
389
    def object_copy(self, object, destination, format='json', ignore_content_type=False,
390
        if_etag_match=None, if_etag_not_match=None, destination_account=None,
391
        content_type=None, content_encoding=None, content_disposition=None, source_version=None,
392
        permitions=None, public=False, metadata=None, *args, **kwargs):
499
    def object_copy(self, object, destination,
500
        format='json',
501
        ignore_content_type=False,
502
        if_etag_match=None,
503
        if_etag_not_match=None,
504
        destination_account=None,
505
        content_type=None,
506
        content_encoding=None,
507
        content_disposition=None,
508
        source_version=None,
509
        permissions=None,
510
        public=False,
511
        metadata=None,
512
        *args,
513
        **kwargs):
393 514
        """ Full Pithos+ COPY at object level
394 515
        --- request parameters ---
395 516
        @param format (string): json (default) or xml
......
399 520
                with etag matching with this
400 521
        @param if_etag_not_match (string): if provided, copy only results
401 522
                with etag not matching with this
402
        @param destination (string): The destination path in the form /<container>/<object>
523
        @param destination (string): The destination path in the form
524
            /<container>/<object>
403 525
        @param destination_account (string): The destination account to copy to
404 526
        @param content_type (string): The MIME content type of the object
405 527
        @param content_encoding (string): The encoding of the object
406
        @param content_disposition (string): The presentation style of the object
528
        @param content_disposition (string): Object resentation style
407 529
        @param source_version (string): The source version to copy from
408
        @param permitions (dict): Object permissions in the form (all fields are optional)
409
                {'read':[user1, group1, user2, ...], 'write':['user3, group2, group3, ...]}
410
                permitions override source permitions, removing any old permitions
411
        @param public (bool): If true, Object is publicly accessible, if else, not
530
        @param permissions (dict): Object permissions in the form
531
            (all fields are optional)
532
            {   'read':[user1, group1, user2, ...],
533
                'write':['user3, group2, group3, ...]
534
            }
535
            permissions override source permissions,
536
            removing any old permissions
537
        @param public (bool): If true, Object is publicly accessible
412 538
        @param metadata (dict): Optional user defined metadata in the form
413
                {'meta-key-1':'meta-value-1', 'meta-key-2':'meta-value-2', ...}
414
                Metadata are appended to the source metadata. In case of same keys, they
415
                replace the old metadata
539
            {'meta-key-1':'meta-value-1', 'meta-key-2':'meta-value-2', ...}
540
            Metadata are appended to the source metadata. In case of same
541
            keys, they replace the old metadata
416 542
        """
417 543
        self.assert_container()
418 544

  
......
428 554
        self.set_header('Content-Disposition', content_disposition)
429 555
        self.set_header('X-Source-Version', source_version)
430 556
        perms = None
431
        if permitions is not None:
432
            for permition_type, permition_list in permitions.items():
557
        if permissions:
558
            for permission_type, permission_list in permissions.items():
433 559
                if perms is None:
434
                    perms = '' #Remove permitions
435
                if len(permition_list) == 0:
560
                    perms = ''  # Remove permissions
561
                if len(permission_list) == 0:
436 562
                    continue
437
                perms += ';'+permition_type if len(perms) > 0 else permition_type
438
                perms += '='+list2str(permition_list, seperator=',')
563
                if len(perms):
564
                    perms += ';'
565
                perms += '%s=%s'\
566
                % (permission_type, list2str(permission_list, seperator=','))
439 567
        self.set_header('X-Object-Sharing', perms)
440 568
        self.set_header('X-Object-Public', public)
441 569
        if metadata is not None:
442 570
            for key, val in metadata.items():
443
                self.set_header('X-Object-Meta-'+key, val)
571
                self.set_header('X-Object-Meta-' + key, val)
444 572

  
445 573
        path = path4url(self.account, self.container, object)
446 574
        success = kwargs.pop('success', 201)
447 575
        return self.copy(path, *args, success=success, **kwargs)
448 576

  
449
    def object_move(self, object, format='json', ignore_content_type=False,
450
        if_etag_match=None, if_etag_not_match=None, destination=None, destination_account=None,
451
        content_type=None, content_encoding=None, content_disposition=None, permitions={},
452
        public=False, metadata={}, *args, **kwargs):
577
    def object_move(self, object,
578
        format='json',
579
        ignore_content_type=False,
580
        if_etag_match=None,
581
        if_etag_not_match=None,
582
        destination=None,
583
        destination_account=None,
584
        content_type=None,
585
        content_encoding=None,
586
        content_disposition=None,
587
        permissions={},
588
        public=False,
589
        metadata={},
590
        *args,
591
        **kwargs):
453 592
        """ Full Pithos+ COPY at object level
454 593
        --- request parameters ---
455 594
        @param format (string): json (default) or xml
......
459 598
                with etag matching with this
460 599
        @param if_etag_not_match (string): if provided, return only results
461 600
                with etag not matching with this
462
        @param destination (string): The destination path in the form /<container>/<object>
601
        @param destination (string): The destination path in the form
602
            /<container>/<object>
463 603
        @param destination_account (string): The destination account to copy to
464 604
        @param content_type (string): The MIME content type of the object
465 605
        @param content_encoding (string): The encoding of the object
466
        @param content_disposition (string): The presentation style of the object
606
        @param content_disposition (string): Object presentation style
467 607
        @param source_version (string): The source version to copy from
468
        @param permitions (dict): Object permissions in the form (all fields are optional)
469
                {'read':[user1, group1, user2, ...], 'write':['user3, group2, group3, ...]}
470
        @param public (bool): If true, Object is publicly accessible, if false, not
608
        @param permissions (dict): Object permissions in the form
609
            (all fields are optional)
610
            {   'read':[user1, group1, user2, ...],
611
                'write':['user3, group2, group3, ...]
612
            }
613
        @param public (bool): If true, Object is publicly accessible
471 614
        @param metadata (dict): Optional user defined metadata in the form
472 615
                {'meta-key-1':'meta-value-1', 'meta-key-2':'meta-value-2', ...}
473 616
        """
......
484 627
        self.set_header('Content-Encoding', content_encoding)
485 628
        self.set_header('Content-Disposition', content_disposition)
486 629
        perms = None
487
        for permition_type, permition_list in permitions.items():
630
        for permission_type, permission_list in permissions.items():
488 631
            if perms is None:
489
                perms = '' #Remove permitions
490
            if len(permition_list) == 0:
632
                perms = ''  # Remove permissions
633
            if len(permission_list) == 0:
491 634
                continue
492
            perms += ';'+permition_type if len(perms) > 0 else permition_type
493
            perms += '='+list2str(permition_list, seperator=',')
635
            if len(perms):
636
                perms += ';'
637
            perms += '%s=%s'\
638
            % (permission_type, list2str(permission_list, seperator=','))
494 639
        self.set_header('X-Object-Sharing', perms)
495 640
        self.set_header('X-Object-Public', public)
496 641
        for key, val in metadata.items():
497
            self.set_header('X-Object-Meta-'+key, val)
642
            self.set_header('X-Object-Meta-' + key, val)
498 643

  
499 644
        path = path4url(self.account, self.container, object)
500 645
        success = kwargs.pop('success', 201)
501 646
        return self.move(path, *args, success=success, **kwargs)
502 647

  
503
    def object_post(self, object, format='json', update=True,
504
        if_etag_match=None, if_etag_not_match=None, content_length=None, content_type=None,
505
        content_range=None, transfer_encoding=None, content_encoding=None, content_disposition=None,
506
        source_object=None, source_account=None, source_version=None, object_bytes=None,
507
        manifest=None, permitions={}, public=False, metadata={}, *args, **kwargs):
648
    def object_post(self, object,
649
        format='json',
650
        update=True,
651
        if_etag_match=None,
652
        if_etag_not_match=None,
653
        content_length=None,
654
        content_type=None,
655
        content_range=None,
656
        transfer_encoding=None,
657
        content_encoding=None,
658
        content_disposition=None,
659
        source_object=None,
660
        source_account=None,
661
        source_version=None,
662
        object_bytes=None,
663
        manifest=None,
664
        permissions={},
665
        public=False,
666
        metadata={},
667
        *args,
668
        **kwargs):
508 669
        """ Full Pithos+ POST at object level
509 670
        --- request parameters ---
510 671
        @param format (string): json (default) or xml
......
517 678
        @param content_length (string): The size of the data written
518 679
        @param content_type (string): The MIME content type of the object
519 680
        @param content_range (string): The range of data supplied
520
        @param transfer_encoding (string): Set to chunked to specify incremental uploading
521
                (if used, Content-Length is ignored)
681
        @param transfer_encoding (string): Set to chunked to specify
682
            incremental uploading (if used, Content-Length is ignored)
522 683
        @param content_encoding (string): The encoding of the object
523
        @param content_disposition (string): The presentation style of the object
524
        @param source_object (string): Update with data from the object at path /<container>/<object>
684
        @param content_disposition (string): Object presentation style
685
        @param source_object (string): Update with data from the object at
686
            path /<container>/<object>
525 687
        @param source_account (string): The source account to update from
526 688
        @param source_version (string): The source version to copy from
527 689
        @param object_bytes (integer): The updated objects final size
528
        @param manifest (string): Object parts prefix in /<container>/<object> form
529
        @param permitions (dict): Object permissions in the form (all fields are optional)
530
                {'read':[user1, group1, user2, ...], 'write':['user3, group2, group3, ...]}
531
        @param public (bool): If true, Object is publicly accessible, if false, not
690
        @param manifest (string): Object parts prefix as /<container>/<object>
691
        @param permissions (dict): Object permissions in the form (all fields
692
            are optional)
693
            {   'read':[user1, group1, user2, ...],
694
                'write':['user3, group2, group3, ...]
695
            }
696
        @param public (bool): If true, Object is publicly accessible
532 697
        @param metadata (dict): Optional user defined metadata in the form
533 698
                {'meta-key-1':'meta-value-1', 'meta-key-2':'meta-value-2', ...}
534 699
        """
535 700
        self.assert_container()
536 701

  
537 702
        self.set_param('format', format, iff=format is not None)
538
        self.set_param('update', iff = update)
703
        self.set_param('update', iff=update)
539 704

  
540 705
        self.set_header('If-Match', if_etag_match)
541 706
        self.set_header('If-None-Match', if_etag_not_match)
542
        self.set_header('Content-Length', content_length, iff=transfer_encoding is None)
707
        self.set_header('Content-Length',
708
            content_length,
709
            iff=transfer_encoding is None)
543 710
        self.set_header('Content-Type', content_type)
544 711
        self.set_header('Content-Range', content_range)
545 712
        self.set_header('Transfer-Encoding', transfer_encoding)
......
551 718
        self.set_header('X-Object-Bytes', object_bytes)
552 719
        self.set_header('X-Object-Manifest', manifest)
553 720
        perms = None
554
        for permition_type, permition_list in permitions.items():
721
        for permission_type, permission_list in permissions.items():
555 722
            if perms is None:
556
                perms = '' #Remove permitions
557
            if len(permition_list) == 0:
723
                perms = ''  # Remove permissions
724
            if len(permission_list) == 0:
558 725
                continue
559
            perms += ';'+permition_type if len(perms) > 0 else permition_type
560
            perms += '='+list2str(permition_list, seperator=',')
726
            if len(perms):
727
                perms += ';'
728
            perms += '%s=%s'\
729
            % (permission_type, list2str(permission_list, seperator=','))
561 730
        self.set_header('X-Object-Sharing', perms)
562 731
        self.set_header('X-Object-Public', public)
563 732
        for key, val in metadata.items():
564
            self.set_header('X-Object-Meta-'+key, val)
733
            self.set_header('X-Object-Meta-' + key, val)
565 734

  
566 735
        path = path4url(self.account, self.container, object)
567
        success=kwargs.pop('success', (202, 204))
736
        success = kwargs.pop('success', (202, 204))
568 737
        return self.post(path, *args, success=success, **kwargs)
569
       
570
    def object_delete(self, object, until=None, delimiter=None, *args, **kwargs):
738

  
739
    def object_delete(self, object,
740
        until=None,
741
        delimiter=None,
742
        *args,
743
        **kwargs):
571 744
        """ Full Pithos+ DELETE at object level
572
        --- request parameters --- 
745
        --- request parameters ---
573 746
        @param until (string): Optional timestamp
574 747
        """
575 748
        self.assert_container()
......
579 752

  
580 753
        path = path4url(self.account, self.container, object)
581 754
        success = kwargs.pop('success', 204)
582
        return self.delete(path, *args, success=success, **kwargs)
755
        return self.delete(path, *args, success=success, **kwargs)

Also available in: Unified diff