9
9
######################################################################
10
10
from __future__ import annotations
11
11
12
+ import datetime as dt
12
13
import re
13
14
from copy import deepcopy
14
15
from typing import TYPE_CHECKING , Any
19
20
from .progress import AbstractProgressListener
20
21
from .replication .types import ReplicationStatus
21
22
from .utils import Sha1HexDigest , b2_url_decode
23
+ from .utils .http_date import parse_http_date
22
24
from .utils .range_ import Range
23
25
24
26
if TYPE_CHECKING :
@@ -49,7 +51,6 @@ class BaseFileVersion:
49
51
'file_retention' ,
50
52
'mod_time_millis' ,
51
53
'replication_status' ,
52
- 'cache_control' ,
53
54
]
54
55
_TYPE_MATCHER = re .compile ('[a-z0-9]+_[a-z0-9]+_f([0-9]).*' )
55
56
_FILE_TYPE = {
@@ -73,7 +74,6 @@ def __init__(
73
74
file_retention : FileRetentionSetting = NO_RETENTION_FILE_SETTING ,
74
75
legal_hold : LegalHold = LegalHold .UNSET ,
75
76
replication_status : ReplicationStatus | None = None ,
76
- cache_control : str | None = None ,
77
77
):
78
78
self .api = api
79
79
self .id_ = id_
@@ -87,7 +87,6 @@ def __init__(
87
87
self .file_retention = file_retention
88
88
self .legal_hold = legal_hold
89
89
self .replication_status = replication_status
90
- self .cache_control = cache_control
91
90
92
91
if SRC_LAST_MODIFIED_MILLIS in self .file_info :
93
92
self .mod_time_millis = int (self .file_info [SRC_LAST_MODIFIED_MILLIS ])
@@ -128,7 +127,6 @@ def _get_args_for_clone(self):
128
127
'file_retention' : self .file_retention ,
129
128
'legal_hold' : self .legal_hold ,
130
129
'replication_status' : self .replication_status ,
131
- 'cache_control' : self .cache_control ,
132
130
} # yapf: disable
133
131
134
132
def as_dict (self ):
@@ -140,7 +138,6 @@ def as_dict(self):
140
138
'serverSideEncryption' : self .server_side_encryption .as_dict (),
141
139
'legalHold' : self .legal_hold .value ,
142
140
'fileRetention' : self .file_retention .as_dict (),
143
- 'cacheControl' : self .cache_control ,
144
141
}
145
142
146
143
if self .size is not None :
@@ -259,7 +256,6 @@ def __init__(
259
256
file_retention : FileRetentionSetting = NO_RETENTION_FILE_SETTING ,
260
257
legal_hold : LegalHold = LegalHold .UNSET ,
261
258
replication_status : ReplicationStatus | None = None ,
262
- cache_control : str | None = None ,
263
259
):
264
260
self .account_id = account_id
265
261
self .bucket_id = bucket_id
@@ -279,9 +275,36 @@ def __init__(
279
275
file_retention = file_retention ,
280
276
legal_hold = legal_hold ,
281
277
replication_status = replication_status ,
282
- cache_control = cache_control ,
283
278
)
284
279
280
+ @property
281
+ def cache_control (self ) -> str | None :
282
+ return self .file_info .get ('b2-cache-control' )
283
+
284
+ @property
285
+ def expires (self ) -> str | None :
286
+ return self .file_info .get ('b2-expires' )
287
+
288
+ def expires_parsed (self ) -> dt .datetime | None :
289
+ """Return the expiration date as a datetime object, or None if there is no expiration date.
290
+ Raise ValueError if `expires` property is not a valid HTTP-date."""
291
+
292
+ if self .expires is None :
293
+ return None
294
+ return parse_http_date (self .expires )
295
+
296
+ @property
297
+ def content_disposition (self ) -> str | None :
298
+ return self .file_info .get ('b2-content-disposition' )
299
+
300
+ @property
301
+ def content_encoding (self ) -> str | None :
302
+ return self .file_info .get ('b2-content-encoding' )
303
+
304
+ @property
305
+ def content_language (self ) -> str | None :
306
+ return self .file_info .get ('b2-content-language' )
307
+
285
308
def _get_args_for_clone (self ):
286
309
args = super ()._get_args_for_clone ()
287
310
args .update (
@@ -352,7 +375,6 @@ def _get_upload_headers(self) -> bytes:
352
375
server_side_encryption = sse ,
353
376
file_retention = self .file_retention ,
354
377
legal_hold = self .legal_hold ,
355
- cache_control = self .cache_control ,
356
378
)
357
379
358
380
headers_str = '' .join (
@@ -381,8 +403,8 @@ class DownloadVersion(BaseFileVersion):
381
403
'content_disposition' ,
382
404
'content_length' ,
383
405
'content_language' ,
384
- '_expires ' ,
385
- '_cache_control ' ,
406
+ 'expires ' ,
407
+ 'cache_control ' ,
386
408
'content_encoding' ,
387
409
]
388
410
@@ -412,8 +434,8 @@ def __init__(
412
434
self .content_disposition = content_disposition
413
435
self .content_length = content_length
414
436
self .content_language = content_language
415
- self ._expires = expires # TODO: parse the string representation of this timestamp to datetime in DownloadVersionFactory
416
- self ._cache_control = cache_control # TODO: parse the string representation of this mapping to dict in DownloadVersionFactory
437
+ self .expires = expires
438
+ self .cache_control = cache_control
417
439
self .content_encoding = content_encoding
418
440
419
441
super ().__init__ (
@@ -429,9 +451,30 @@ def __init__(
429
451
file_retention = file_retention ,
430
452
legal_hold = legal_hold ,
431
453
replication_status = replication_status ,
432
- cache_control = cache_control ,
433
454
)
434
455
456
+ def expires_parsed (self ) -> dt .datetime | None :
457
+ """Return the expiration date as a datetime object, or None if there is no expiration date.
458
+ Raise ValueError if `expires` property is not a valid HTTP-date."""
459
+
460
+ if self .expires is None :
461
+ return None
462
+ return parse_http_date (self .expires )
463
+
464
+ def as_dict (self ) -> dict :
465
+ result = super ().as_dict ()
466
+ if self .cache_control is not None :
467
+ result ['cacheControl' ] = self .cache_control
468
+ if self .expires is not None :
469
+ result ['expires' ] = self .expires
470
+ if self .content_disposition is not None :
471
+ result ['contentDisposition' ] = self .content_disposition
472
+ if self .content_encoding is not None :
473
+ result ['contentEncoding' ] = self .content_encoding
474
+ if self .content_language is not None :
475
+ result ['contentLanguage' ] = self .content_language
476
+ return result
477
+
435
478
def _get_args_for_clone (self ):
436
479
args = super ()._get_args_for_clone ()
437
480
args .update (
@@ -440,8 +483,8 @@ def _get_args_for_clone(self):
440
483
'content_disposition' : self .content_disposition ,
441
484
'content_length' : self .content_length ,
442
485
'content_language' : self .content_language ,
443
- 'expires' : self ._expires ,
444
- 'cache_control' : self ._cache_control ,
486
+ 'expires' : self .expires ,
487
+ 'cache_control' : self .cache_control ,
445
488
'content_encoding' : self .content_encoding ,
446
489
}
447
490
)
@@ -516,7 +559,6 @@ def from_api_response(self, file_version_dict, force_action=None):
516
559
replication_status_value = file_version_dict .get ('replicationStatus' )
517
560
replication_status = replication_status_value and ReplicationStatus [
518
561
replication_status_value .upper ()]
519
- cache_control = file_version_dict .get ('cacheControl' )
520
562
521
563
return self .FILE_VERSION_CLASS (
522
564
self .api ,
@@ -535,7 +577,6 @@ def from_api_response(self, file_version_dict, force_action=None):
535
577
file_retention ,
536
578
legal_hold ,
537
579
replication_status ,
538
- cache_control ,
539
580
)
540
581
541
582
@@ -575,11 +616,6 @@ def from_response_headers(self, headers):
575
616
size = content_length = int (headers ['Content-Length' ])
576
617
range_ = Range (0 , max (size - 1 , 0 ))
577
618
578
- if 'Cache-Control' in headers :
579
- cache_control = b2_url_decode (headers ['Cache-Control' ])
580
- else :
581
- cache_control = None
582
-
583
619
return DownloadVersion (
584
620
api = self .api ,
585
621
id_ = headers ['x-bz-file-id' ],
@@ -595,7 +631,7 @@ def from_response_headers(self, headers):
595
631
content_length = content_length ,
596
632
content_language = headers .get ('Content-Language' ),
597
633
expires = headers .get ('Expires' ),
598
- cache_control = cache_control ,
634
+ cache_control = headers . get ( 'Cache-Control' ) ,
599
635
content_encoding = headers .get ('Content-Encoding' ),
600
636
file_retention = FileRetentionSetting .from_response_headers (headers ),
601
637
legal_hold = LegalHold .from_response_headers (headers ),
0 commit comments