Skip to content

Commit b8d47df

Browse files
Merge pull request #272 from reef-technologies/get_fresh_state
get_fresh_state method added to FileVersion and Bucket
2 parents c3cd602 + 41a1eda commit b8d47df

File tree

10 files changed

+96
-6
lines changed

10 files changed

+96
-6
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Added
10+
* `get_fresh_state` method added to `FileVersion` and `Bucket`
11+
912
### Changed
1013
* `download_file_*` methods refactored to allow for inspecting DownloadVersion before downloading the whole file
1114
* `B2Api.get_file_info` returns a `FileVersion` object in v2

b2sdk/_v2/exception.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from b2sdk.exception import BadFileInfo
2626
from b2sdk.exception import BadJson
2727
from b2sdk.exception import BadUploadUrl
28+
from b2sdk.exception import BucketIdNotFound
2829
from b2sdk.exception import BrokenPipe
2930
from b2sdk.exception import BucketNotAllowed
3031
from b2sdk.exception import CapabilityNotAllowed
@@ -95,6 +96,7 @@
9596
'BadJson',
9697
'BadUploadUrl',
9798
'BrokenPipe',
99+
'BucketIdNotFound',
98100
'BucketNotAllowed',
99101
'CapabilityNotAllowed',
100102
'CapExceeded',

b2sdk/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .cache import AbstractCache
1717
from .bucket import Bucket, BucketFactory
1818
from .encryption.setting import EncryptionSetting
19-
from .exception import NonExistentBucket, RestrictedBucket
19+
from .exception import BucketIdNotFound, NonExistentBucket, RestrictedBucket
2020
from .file_lock import FileRetentionSetting, LegalHold
2121
from .file_version import DownloadVersionFactory, FileIdAndName, FileVersion, FileVersionFactory
2222
from .large_file.services import LargeFileServices
@@ -286,7 +286,7 @@ def get_bucket_by_id(self, bucket_id: str) -> Bucket:
286286
return bucket
287287

288288
# There is no such bucket.
289-
raise NonExistentBucket(bucket_name)
289+
raise BucketIdNotFound(bucket_id)
290290

291291
def get_bucket_by_name(self, bucket_name):
292292
"""

b2sdk/bucket.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from .encryption.setting import EncryptionSetting, EncryptionSettingFactory
1515
from .encryption.types import EncryptionMode
16-
from .exception import FileNotPresent, FileOrBucketNotFound, UnexpectedCloudBehaviour, UnrecognizedBucketType
16+
from .exception import BucketIdNotFound, FileNotPresent, FileOrBucketNotFound, UnexpectedCloudBehaviour, UnrecognizedBucketType
1717
from .file_lock import (
1818
BucketRetentionSetting,
1919
FileLockConfiguration,
@@ -88,6 +88,16 @@ def __init__(
8888
self.default_retention = default_retention
8989
self.is_file_lock_enabled = is_file_lock_enabled
9090

91+
def get_fresh_state(self) -> 'Bucket':
92+
"""
93+
Fetch all the information about this bucket and return a new bucket object.
94+
This method does NOT change the object it is called on.
95+
"""
96+
buckets_found = self.api.list_buckets(bucket_id=self.id_)
97+
if not buckets_found:
98+
raise BucketIdNotFound(self.id_)
99+
return buckets_found[0]
100+
91101
def get_id(self):
92102
"""
93103
Return bucket ID.

b2sdk/exception.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@ def __str__(self):
244244
return 'Could not find %s within %s' % (file_str, bucket_str)
245245

246246

247+
class BucketIdNotFound(ResourceNotFound):
248+
def __init__(self, bucket_id):
249+
self.bucket_id = bucket_id
250+
251+
def __str__(self):
252+
return 'Bucket with id=%s not found' % (self.bucket_id,)
253+
254+
247255
class FileAlreadyHidden(B2SimpleError):
248256
pass
249257

b2sdk/file_version.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,13 @@ def as_dict(self):
182182

183183
return result
184184

185+
def get_fresh_state(self) -> 'FileVersion':
186+
"""
187+
Fetch all the information about this file version and return a new FileVersion object.
188+
This method does NOT change the object it is called on.
189+
"""
190+
return self.api.get_file_info(self.id_)
191+
185192

186193
class DownloadVersion(BaseFileVersion):
187194
"""

b2sdk/v1/file_version.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
# Override to retain legacy class name, __init__ signature, slots
2020
# and old formatting methods
2121
# and to omit 'api' property when doing __eq__ and __repr__
22+
# and to make get_fresh_state return proper objects, even though v1.B2Api.get_file_info returns dicts
2223
class FileVersionInfo(v2.FileVersion):
2324
__slots__ = ['_api']
2425

@@ -92,6 +93,13 @@ def format_ls_entry(self):
9293
def format_folder_ls_entry(cls, name):
9394
return cls.LS_ENTRY_TEMPLATE % ('-', '-', '-', '-', 0, name)
9495

96+
def get_fresh_state(self) -> 'FileVersionInfo':
97+
"""
98+
Fetch all the information about this file version and return a new FileVersion object.
99+
This method does NOT change the object it is called on.
100+
"""
101+
return self.api.file_version_factory.from_api_response(self.api.get_file_info(self.id_))
102+
95103

96104
def file_version_info_from_new_file_version(file_version: v2.FileVersion) -> FileVersionInfo:
97105
return FileVersionInfo(

test/unit/bucket/test_bucket.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
AlreadyFailed,
2323
B2Error,
2424
B2RequestTimeoutDuringUpload,
25+
BucketIdNotFound,
2526
InvalidAuthToken,
2627
InvalidMetadataDirective,
2728
InvalidRange,
@@ -39,7 +40,7 @@
3940
from apiver_deps import FileVersion as VFileVersionInfo
4041
from apiver_deps import B2Api
4142
from apiver_deps import B2HttpApiConfig
42-
from apiver_deps import Bucket
43+
from apiver_deps import Bucket, BucketFactory
4344
from apiver_deps import DownloadedFile
4445
from apiver_deps import DownloadVersion
4546
from apiver_deps import LargeFileUploadState
@@ -477,6 +478,26 @@ def test_delete_file_version(self):
477478
self.assertBucketContents(expected, '', show_versions=True)
478479

479480

481+
class TestGetFreshState(TestCaseWithBucket):
482+
def test_ok(self):
483+
same_but_different = self.api.get_bucket_by_id(self.bucket.id_)
484+
same_but_different = same_but_different.get_fresh_state()
485+
assert isinstance(same_but_different, Bucket)
486+
assert id(same_but_different) != id(self.bucket)
487+
assert same_but_different.as_dict() == self.bucket.as_dict()
488+
same_but_different = same_but_different.update(bucket_info={'completely': 'new info'})
489+
if apiver_deps.V <= 1:
490+
same_but_different = BucketFactory.from_api_bucket_dict(self.api, same_but_different)
491+
assert same_but_different.as_dict() != self.bucket.as_dict()
492+
refreshed_bucket = self.bucket.get_fresh_state()
493+
assert same_but_different.as_dict() == refreshed_bucket.as_dict()
494+
495+
def test_fail(self):
496+
self.api.delete_bucket(self.bucket)
497+
with pytest.raises(BucketIdNotFound):
498+
self.bucket.get_fresh_state()
499+
500+
480501
class TestListVersions(TestCaseWithBucket):
481502
def test_single_version(self):
482503
data = b'hello world'

test/unit/file_version/test_file_version.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
import pytest
1212

1313
import apiver_deps
14+
from apiver_deps import B2Api
15+
from apiver_deps import B2HttpApiConfig
16+
from apiver_deps import DummyCache
17+
from apiver_deps import InMemoryAccountInfo
18+
from apiver_deps import LegalHold
19+
from apiver_deps import RawSimulator
1420

1521
if apiver_deps.V <= 1:
1622
from apiver_deps import FileVersionInfo as VFileVersion
@@ -19,6 +25,17 @@
1925

2026

2127
class TestFileVersion:
28+
@pytest.fixture(autouse=True)
29+
def setUp(self):
30+
self.account_info = InMemoryAccountInfo()
31+
self.cache = DummyCache()
32+
self.api = B2Api(
33+
self.account_info, self.cache, api_config=B2HttpApiConfig(_raw_api_class=RawSimulator)
34+
)
35+
self.raw_api = self.api.session.raw_api
36+
(self.application_key_id, self.master_key) = self.raw_api.create_account()
37+
self.api.authorize_account('production', self.application_key_id, self.master_key)
38+
2239
@pytest.mark.apiver(to_ver=1)
2340
def test_format_ls_entry(self):
2441
file_version_info = VFileVersion(
@@ -30,3 +47,17 @@ def test_format_ls_entry(self):
3047
'00:00:02 200 inner/a.txt'
3148
)
3249
assert expected_entry == file_version_info.format_ls_entry()
50+
51+
def test_get_fresh_state(self):
52+
self.bucket = self.api.create_bucket('testbucket', 'allPrivate', is_file_lock_enabled=True)
53+
initial_file_version = self.bucket.upload_bytes(b'nothing', 'test_file')
54+
self.api.update_file_legal_hold(
55+
initial_file_version.id_, initial_file_version.file_name, LegalHold.ON
56+
)
57+
fetched_version = self.api.get_file_info(initial_file_version.id_)
58+
if apiver_deps.V <= 1:
59+
fetched_version = self.api.file_version_factory.from_api_response(fetched_version)
60+
assert initial_file_version.as_dict() != fetched_version.as_dict()
61+
refreshed_version = initial_file_version.get_fresh_state()
62+
assert isinstance(refreshed_version, VFileVersion)
63+
assert refreshed_version.as_dict() == fetched_version.as_dict()

test/unit/v_all/test_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from apiver_deps import EncryptionSetting
1919
from apiver_deps import InMemoryAccountInfo
2020
from apiver_deps import RawSimulator
21-
from apiver_deps_exception import NonExistentBucket
21+
from apiver_deps_exception import BucketIdNotFound
2222
from ..test_base import TestBase
2323

2424

@@ -56,7 +56,7 @@ def test_get_bucket_by_id_up_to_v1(self):
5656
@pytest.mark.apiver(from_ver=2)
5757
def test_get_bucket_by_id_v2(self):
5858
self._authorize_account()
59-
with pytest.raises(NonExistentBucket):
59+
with pytest.raises(BucketIdNotFound):
6060
self.api.get_bucket_by_id("this id doesn't even exist")
6161
created_bucket = self.api.create_bucket('bucket1', 'allPrivate')
6262
read_bucket = self.api.get_bucket_by_id(created_bucket.id_)

0 commit comments

Comments
 (0)