diff --git a/b2sdk/_internal/raw_api.py b/b2sdk/_internal/raw_api.py index 0fe2d84dd..93446c92a 100644 --- a/b2sdk/_internal/raw_api.py +++ b/b2sdk/_internal/raw_api.py @@ -553,7 +553,7 @@ def _post_json(self, base_url: str, endpoint: str, auth: str, **params) -> JSON: :param args: the rest of the parameters are passed to b2 :return: the decoded JSON response """ - url = f'{base_url}/b2api/{API_VERSION}/{endpoint}' + url = f'{base_url}/b2api/{self.API_VERSION}/{endpoint}' headers = {'Authorization': auth} return self.b2_http.post_json_return_json(url, headers, params) diff --git a/b2sdk/v2/api.py b/b2sdk/v2/api.py index afd3ecc0d..8044e667e 100644 --- a/b2sdk/v2/api.py +++ b/b2sdk/v2/api.py @@ -25,6 +25,8 @@ from .file_version import FileVersionFactory from .large_file import LargeFileServices from .application_key import FullApplicationKey, ApplicationKey, BaseApplicationKey +from .account_info import AbstractAccountInfo +from .api_config import DEFAULT_HTTP_API_CONFIG, B2HttpApiConfig class Services(v3.Services): @@ -48,10 +50,29 @@ class B2Api(v3.B2Api): API_VERSION = RAW_API_VERSION # Legacy init in case something depends on max_workers defaults = 10 - def __init__(self, *args, **kwargs): - kwargs.setdefault('max_upload_workers', 10) - kwargs.setdefault('max_copy_workers', 10) - super().__init__(*args, **kwargs) + def __init__( + self, + account_info: AbstractAccountInfo | None = None, + cache: v3.AbstractCache | None = None, + max_upload_workers: int | None = 10, + max_copy_workers: int | None = 10, + api_config: B2HttpApiConfig = DEFAULT_HTTP_API_CONFIG, + max_download_workers: int | None = None, + save_to_buffer_size: int | None = None, + check_download_hash: bool = True, + max_download_streams_per_file: int | None = None, + ): + super().__init__( + account_info=account_info, + cache=cache, + max_upload_workers=max_upload_workers, + max_copy_workers=max_copy_workers, + api_config=api_config, + max_download_workers=max_download_workers, + save_to_buffer_size=save_to_buffer_size, + check_download_hash=check_download_hash, + max_download_streams_per_file=max_download_streams_per_file, + ) def get_bucket_by_id(self, bucket_id: str) -> v3.Bucket: try: diff --git a/b2sdk/v2/api_config.py b/b2sdk/v2/api_config.py new file mode 100644 index 000000000..7773b2ae8 --- /dev/null +++ b/b2sdk/v2/api_config.py @@ -0,0 +1,18 @@ +###################################################################### +# +# File: b2sdk/v2/api_config.py +# +# Copyright 2025 Backblaze Inc. All Rights Reserved. +# +# License https://www.backblaze.com/using_b2_code.html +# +###################################################################### +from b2sdk import v3 +from .raw_api import B2RawHTTPApi + + +class B2HttpApiConfig(v3.B2HttpApiConfig): + DEFAULT_RAW_API_CLASS = B2RawHTTPApi + + +DEFAULT_HTTP_API_CONFIG = B2HttpApiConfig() diff --git a/b2sdk/v2/session.py b/b2sdk/v2/session.py index a6ce6d6e9..61f09039a 100644 --- a/b2sdk/v2/session.py +++ b/b2sdk/v2/session.py @@ -12,14 +12,16 @@ from b2sdk import v3 from .b2http import B2Http +from .account_info import SqliteAccountInfo from ._compat import _file_infos_rename -from .._internal import api_config as _api_config +from . import api_config as _api_config from .._internal import cache as _cache from .._internal.account_info import abstract as _abstract # Override to use legacy B2Http class B2Session(v3.B2Session): + SQLITE_ACCOUNT_INFO_CLASS = staticmethod(SqliteAccountInfo) B2HTTP_CLASS = staticmethod(B2Http) def __init__( @@ -31,6 +33,7 @@ def __init__( if account_info is not None and cache is None: # preserve legacy behavior https://github.com/Backblaze/b2-sdk-python/issues/497#issuecomment-2147461352 cache = _cache.DummyCache() + super().__init__(account_info, cache, api_config) def create_key( diff --git a/changelog.d/540.fixed.md b/changelog.d/540.fixed.md new file mode 100644 index 000000000..034cb7e8a --- /dev/null +++ b/changelog.d/540.fixed.md @@ -0,0 +1 @@ +Fix incorrect reliance on v3 abstractions in apiver v2. \ No newline at end of file diff --git a/test/unit/v2/test_session.py b/test/unit/v2/test_session.py index cd5db1cca..003c535ac 100644 --- a/test/unit/v2/test_session.py +++ b/test/unit/v2/test_session.py @@ -15,7 +15,7 @@ from apiver_deps_exception import Unauthorized from b2sdk import v3 -from b2sdk.v2 import B2Session +from b2sdk.v2 import B2Http, B2RawHTTPApi, B2Session from test.helpers import patch_bind_params from ..account_info.fixtures import * # noqa @@ -74,6 +74,18 @@ def dummy_session(): return B2Session() +def test_session__default_classes_v2(): + session = B2Session() + + assert isinstance(session.raw_api, B2RawHTTPApi), 'Expected v2.B2RawHTTPApi, got %s' % type( + session.raw_api + ) + + assert isinstance(session.raw_api.b2_http, B2Http), 'Expected v2.B2Http, got %s' % type( + session.raw_api.b2_http + ) + + def test_session__upload_file__supports_file_infos(dummy_session, file_info): """Test v2.B2Session.upload_file support of deprecated file_infos param""" with patch_bind_params(v3.B2Session, 'upload_file') as mock_method, pytest.warns( diff --git a/test/unit/v_all/test_api.py b/test/unit/v_all/test_api.py index 93c610d24..d40741e31 100644 --- a/test/unit/v_all/test_api.py +++ b/test/unit/v_all/test_api.py @@ -14,6 +14,7 @@ from apiver_deps import ( B2Api, B2HttpApiConfig, + B2Session, Bucket, EncryptionMode, EncryptionSetting, @@ -73,6 +74,8 @@ def test_api_initialization(self, kwargs, _raw_api_class): self.api = B2Api(self.account_info, self.cache, api_config=api_config, **kwargs) + assert isinstance(self.api.session, B2Session) # ensure correct apiver session is used + assert self.api.account_info is self.account_info assert self.api.api_config is api_config assert self.api.cache is self.cache