From 658cb3d3ba7f5e25fac8fdf45ce023da6b4abe1d Mon Sep 17 00:00:00 2001 From: Olzhas Arystanov Date: Tue, 3 Mar 2026 03:12:39 +0500 Subject: [PATCH] Handle null case when encoding / decoding sha1 in BaseFileVersion --- b2sdk/_internal/file_version.py | 10 ++++++++-- changelog.d/553.fixed.md | 1 + test/unit/file_version/test_file_version.py | 8 ++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 changelog.d/553.fixed.md diff --git a/b2sdk/_internal/file_version.py b/b2sdk/_internal/file_version.py index 85e088635..ae0ccf699 100644 --- a/b2sdk/_internal/file_version.py +++ b/b2sdk/_internal/file_version.py @@ -95,13 +95,19 @@ def __init__( self.mod_time_millis = self.upload_timestamp @classmethod - def _decode_content_sha1(cls, content_sha1): + def _decode_content_sha1(cls, content_sha1: str | None) -> tuple[str | None, bool]: + if content_sha1 is None: + return None, True if content_sha1.startswith(UNVERIFIED_CHECKSUM_PREFIX): return content_sha1[len(UNVERIFIED_CHECKSUM_PREFIX) :], False return content_sha1, True @classmethod - def _encode_content_sha1(cls, content_sha1, content_sha1_verified): + def _encode_content_sha1( + cls, content_sha1: str | None, content_sha1_verified: bool + ) -> str | None: + if content_sha1 is None: + return None if not content_sha1_verified: return f'{UNVERIFIED_CHECKSUM_PREFIX}{content_sha1}' return content_sha1 diff --git a/changelog.d/553.fixed.md b/changelog.d/553.fixed.md new file mode 100644 index 000000000..f98074617 --- /dev/null +++ b/changelog.d/553.fixed.md @@ -0,0 +1 @@ +Handle null case when encoding / decoding `content_sha1` in BaseFileVersion. diff --git a/test/unit/file_version/test_file_version.py b/test/unit/file_version/test_file_version.py index 7674720c5..3079b1571 100644 --- a/test/unit/file_version/test_file_version.py +++ b/test/unit/file_version/test_file_version.py @@ -117,6 +117,14 @@ def test_clone_file_version_and_download_version(self): assert isinstance(cloned, DownloadVersion) assert cloned.as_dict() == {**download_version.as_dict(), 'legalHold': LegalHold.OFF.value} + def test_clone_file_version_with_unknown_sha1(self): + cloned = self.file_version._clone(content_sha1=None) + + assert isinstance(cloned, VFileVersion) + assert cloned.content_sha1 is None + assert cloned.content_sha1_verified is True + assert 'contentSha1' not in cloned.as_dict() + def test_update_legal_hold(self): new_file_version = self.file_version.update_legal_hold(LegalHold.ON) assert isinstance(new_file_version, VFileVersion)