From c9c8336837ad75a944b77a57120465dbb3252c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Nowacki?= Date: Sat, 2 Dec 2023 12:01:19 +0100 Subject: [PATCH 1/5] make `realm` optional in B2Api.authorize_account --- b2sdk/api.py | 4 +- b2sdk/v2/api.py | 10 +++++ changelog.d/+authorize_account.changed.md | 1 + test/unit/api/test_api.py | 48 +++++++++++++++++---- test/unit/bucket/test_bucket.py | 24 +++++++++-- test/unit/file_version/test_file_version.py | 6 ++- test/unit/replication/conftest.py | 6 ++- test/unit/v_all/test_api.py | 6 ++- test/unit/v_all/test_replication.py | 6 ++- 9 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 changelog.d/+authorize_account.changed.md diff --git a/b2sdk/api.py b/b2sdk/api.py index bee11c0de..e76c177cd 100644 --- a/b2sdk/api.py +++ b/b2sdk/api.py @@ -209,13 +209,13 @@ def authorize_automatically(self): return self.session.authorize_automatically() @limit_trace_arguments(only=('self', 'realm')) - def authorize_account(self, realm, application_key_id, application_key): + def authorize_account(self, application_key_id, application_key, realm='production'): """ Perform account authorization. - :param str realm: a realm to authorize account in (usually just "production") :param str application_key_id: :term:`application key ID` :param str application_key: user's :term:`application key` + :param str realm: a realm to authorize account in (usually just "production") """ self.session.authorize_account(realm, application_key_id, application_key) self._populate_bucket_cache_from_key() diff --git a/b2sdk/v2/api.py b/b2sdk/v2/api.py index 40690c0f9..efc33ff90 100644 --- a/b2sdk/v2/api.py +++ b/b2sdk/v2/api.py @@ -28,6 +28,7 @@ class Services(v3.Services): # override to use legacy B2Session with legacy B2Http # and to raise old style BucketIdNotFound exception # and to use old style Bucket +# and to use legacy authorize_account signature class B2Api(v3.B2Api): SESSION_CLASS = staticmethod(B2Session) BUCKET_CLASS = staticmethod(Bucket) @@ -46,3 +47,12 @@ def get_bucket_by_id(self, bucket_id: str) -> v3.Bucket: return super().get_bucket_by_id(bucket_id) except v3BucketIdNotFound as e: raise BucketIdNotFound(e.bucket_id) + + # one should put "@limit_trace_arguments(only=('self', 'realm'))" here but logfury meta magic copies the appropriate + # attributes from base classes + def authorize_account(self, realm, application_key_id, application_key): + return super().authorize_account( + application_key_id=application_key_id, + application_key=application_key, + realm=realm, + ) \ No newline at end of file diff --git a/changelog.d/+authorize_account.changed.md b/changelog.d/+authorize_account.changed.md new file mode 100644 index 000000000..49397c6c0 --- /dev/null +++ b/changelog.d/+authorize_account.changed.md @@ -0,0 +1 @@ +Change v3.B2Api.authorize_account signature to make `realm` optional and `"production"` by default \ No newline at end of file diff --git a/test/unit/api/test_api.py b/test/unit/api/test_api.py index 08151f7bb..46889a88d 100644 --- a/test/unit/api/test_api.py +++ b/test/unit/api/test_api.py @@ -312,7 +312,11 @@ def test_buckets_with_encryption(self): # now check it with no readBucketEncryption permission to see that it's unknown key = create_key(self.api, ['listBuckets'], 'key1') - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) buckets = { b.name: b for b in self.api.list_buckets() # scan again with new key @@ -352,7 +356,11 @@ def test_reauthorize_with_app_key(self): key = create_key(self.api, ['listBuckets'], 'key1') # authorize with the key - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) # expire the auth token we just got self.raw_api.expire_auth_token(self.account_info.get_account_auth_token()) @@ -365,14 +373,22 @@ def test_list_buckets_with_restriction(self): bucket1 = self.api.create_bucket('bucket1', 'allPrivate') self.api.create_bucket('bucket2', 'allPrivate') key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_) - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) assert [b.name for b in self.api.list_buckets(bucket_name=bucket1.name)] == ['bucket1'] def test_get_bucket_by_name_with_bucket_restriction(self): self._authorize_account() bucket1 = self.api.create_bucket('bucket1', 'allPrivate') key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_) - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) assert self.api.get_bucket_by_name('bucket1').id_ == bucket1.id_ def test_list_buckets_with_restriction_and_wrong_name(self): @@ -380,7 +396,11 @@ def test_list_buckets_with_restriction_and_wrong_name(self): bucket1 = self.api.create_bucket('bucket1', 'allPrivate') bucket2 = self.api.create_bucket('bucket2', 'allPrivate') key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_) - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) with pytest.raises(RestrictedBucket) as excinfo: self.api.list_buckets(bucket_name=bucket2.name) assert str(excinfo.value) == 'Application key is restricted to bucket: bucket1' @@ -390,7 +410,11 @@ def test_list_buckets_with_restriction_and_no_name(self): bucket1 = self.api.create_bucket('bucket1', 'allPrivate') self.api.create_bucket('bucket2', 'allPrivate') key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_) - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) with pytest.raises(RestrictedBucket) as excinfo: self.api.list_buckets() assert str(excinfo.value) == 'Application key is restricted to bucket: bucket1' @@ -400,13 +424,21 @@ def test_list_buckets_with_restriction_and_wrong_id(self): bucket1 = self.api.create_bucket('bucket1', 'allPrivate') self.api.create_bucket('bucket2', 'allPrivate') key = create_key(self.api, ['listBuckets'], 'key1', bucket_id=bucket1.id_) - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) with pytest.raises(RestrictedBucket) as excinfo: self.api.list_buckets(bucket_id='not the one bound to the key') assert str(excinfo.value) == f'Application key is restricted to bucket: {bucket1.id_}' def _authorize_account(self): - self.api.authorize_account('production', self.application_key_id, self.master_key) + self.api.authorize_account( + application_key_id=self.application_key_id, + application_key=self.master_key, + realm='production', + ) def test_update_file_retention(self): self._authorize_account() diff --git a/test/unit/bucket/test_bucket.py b/test/unit/bucket/test_bucket.py index f6bb3a04d..06014068f 100644 --- a/test/unit/bucket/test_bucket.py +++ b/test/unit/bucket/test_bucket.py @@ -250,7 +250,11 @@ def setUp(self): self.api = self.get_api() self.simulator = self.api.session.raw_api (self.account_id, self.master_key) = self.simulator.create_account() - self.api.authorize_account('production', self.account_id, self.master_key) + self.api.authorize_account( + application_key_id=self.account_id, + application_key=self.master_key, + realm='production', + ) self.api_url = self.account_info.get_api_url() self.account_auth_token = self.account_info.get_account_auth_token() self.bucket = self.api.create_bucket(self.bucket_name, 'allPublic') @@ -463,7 +467,11 @@ def test_version_by_name_file_lock(self): ] ) - low_perm_api.authorize_account('production', low_perm_key.id_, low_perm_key.application_key) + low_perm_api.authorize_account( + application_key_id=low_perm_key.id_, + application_key=low_perm_key.application_key, + realm='production', + ) low_perm_bucket = low_perm_api.get_bucket_by_name('my-bucket-with-file-lock') file_version = low_perm_bucket.get_file_info_by_name('a') @@ -2680,7 +2688,11 @@ def test_authorize_for_bucket_ensures_cache(self): bucket_id=self.bucket_id, ) - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) # Check whether the bucket fetching performs an API call. with mock.patch.object(self.api, 'list_buckets') as mock_list_buckets: @@ -2702,7 +2714,11 @@ def test_authorize_for_non_existing_bucket(self): ) with self.assertRaises(RestrictedBucketMissing): - self.api.authorize_account('production', key.id_, key.application_key) + self.api.authorize_account( + application_key_id=key.id_, + application_key=key.application_key, + realm='production', + ) class TestDownloadLocalDirectoryIssues(TestCaseWithBucket): diff --git a/test/unit/file_version/test_file_version.py b/test/unit/file_version/test_file_version.py index aad21dd9d..f7c4bfca7 100644 --- a/test/unit/file_version/test_file_version.py +++ b/test/unit/file_version/test_file_version.py @@ -47,7 +47,11 @@ def setUp(self): ) self.raw_api = self.api.session.raw_api (self.application_key_id, self.master_key) = self.raw_api.create_account() - self.api.authorize_account('production', self.application_key_id, self.master_key) + self.api.authorize_account( + application_key_id=self.application_key_id, + application_key=self.master_key, + realm='production', + ) self.bucket = self.api.create_bucket('testbucket', 'allPrivate', is_file_lock_enabled=True) self.file_version = self.bucket.upload_bytes( b'nothing', 'test_file', cache_control='private, max-age=3600' diff --git a/test/unit/replication/conftest.py b/test/unit/replication/conftest.py index 38a1718d2..c91542644 100644 --- a/test/unit/replication/conftest.py +++ b/test/unit/replication/conftest.py @@ -32,7 +32,11 @@ def api() -> B2Api: simulator = api.session.raw_api account_id, master_key = simulator.create_account() - api.authorize_account('production', account_id, master_key) + api.authorize_account( + application_key_id=account_id, + application_key=master_key, + realm='production', + ) # api_url = account_info.get_api_url() # account_auth_token = account_info.get_account_auth_token()1 return api diff --git a/test/unit/v_all/test_api.py b/test/unit/v_all/test_api.py index 782cd9b00..efb2552d3 100644 --- a/test/unit/v_all/test_api.py +++ b/test/unit/v_all/test_api.py @@ -116,7 +116,11 @@ def setUp(self): (self.application_key_id, self.master_key) = self.raw_api.create_account() def _authorize_account(self): - self.api.authorize_account('production', self.application_key_id, self.master_key) + self.api.authorize_account( + realm='production', + application_key_id=self.application_key_id, + application_key=self.master_key, + ) @pytest.mark.apiver(to_ver=1) def test_get_bucket_by_id_up_to_v1(self): diff --git a/test/unit/v_all/test_replication.py b/test/unit/v_all/test_replication.py index ad499f382..8d82721a9 100644 --- a/test/unit/v_all/test_replication.py +++ b/test/unit/v_all/test_replication.py @@ -39,7 +39,11 @@ def setUp(self): self.application_key_id, self.master_key = self.raw_api.create_account() def _authorize_account(self): - self.api.authorize_account('production', self.application_key_id, self.master_key) + self.api.authorize_account( + realm='production', + application_key_id=self.application_key_id, + application_key=self.master_key, + ) @pytest.mark.apiver(from_ver=2) def test_setup_both(self): From 10a40ce9640c90ce77c3d5648e94d1f1c31f788b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Nowacki?= Date: Sat, 2 Dec 2023 21:33:12 +0100 Subject: [PATCH 2/5] Add `-v` to pytest in CI --- .github/workflows/ci.yml | 4 ++-- changelog.d/+make_tests_in_ci_verbose.infrastructure.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelog.d/+make_tests_in_ci_verbose.infrastructure.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 754d4cd1e..8df37d661 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,12 +106,12 @@ jobs: - name: Install dependencies run: python -m pip install --upgrade nox pip setuptools - name: Run unit tests - run: nox -vs unit + run: nox -vs unit -- -v env: SKIP_COVERAGE: ${{ startsWith(matrix.python-version, env.SKIP_COVERAGE_PYTHON_VERSION_PREFIX) }} - name: Run integration tests if: ${{ env.B2_TEST_APPLICATION_KEY != '' && env.B2_TEST_APPLICATION_KEY_ID != '' }} - run: nox -vs integration -- --dont-cleanup-old-buckets + run: nox -vs integration -- --dont-cleanup-old-buckets -v doc: needs: build runs-on: ubuntu-latest diff --git a/changelog.d/+make_tests_in_ci_verbose.infrastructure.md b/changelog.d/+make_tests_in_ci_verbose.infrastructure.md new file mode 100644 index 000000000..3b56d7038 --- /dev/null +++ b/changelog.d/+make_tests_in_ci_verbose.infrastructure.md @@ -0,0 +1 @@ +Add `-v` to pytest in CI \ No newline at end of file From cef9ff178bd6374f5900b72bdacf937c83fa3e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Nowacki?= Date: Sat, 2 Dec 2023 21:51:05 +0100 Subject: [PATCH 3/5] Run windows pypy3.9 tests on nightly builds --- .github/workflows/ci.yml | 9 ++++++++- .../+run_windows_pypy_tests_on_nightly.infrastructure.md | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8df37d661..bdfc13547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: fail-fast: false matrix: os: ["ubuntu-latest", "macos-latest", "windows-latest"] - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.9", "pypy-3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.9", "pypy-3.9-nightly", "pypy-3.10"] exclude: - os: "macos-latest" python-version: "pypy-3.9" @@ -94,6 +94,13 @@ jobs: python-version: "pypy-3.10" - os: "windows-latest" python-version: "pypy-3.10" + # TODO: pypy-3.9 started breaking on windows, due to some prints leftover in pypy release + - os: "ubuntu-latest" + python-version: "pypy-3.9-nightly" + - os: "macos-latest" + python-version: "pypy-3.9-nightly" + - os: "windows-latest" + python-version: "pypy-3.9" steps: - uses: actions/checkout@v3 with: diff --git a/changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md b/changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md new file mode 100644 index 000000000..fe7d8f12c --- /dev/null +++ b/changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md @@ -0,0 +1 @@ +Run windows pypy3.9 tests on nightly builds \ No newline at end of file From 002515a8e1ec81cc0c15147bab133f953537e428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Nowacki?= Date: Mon, 4 Dec 2023 13:12:36 +0100 Subject: [PATCH 4/5] post review fixes --- b2sdk/v2/api.py | 4 ++-- test/unit/api/test_api.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/b2sdk/v2/api.py b/b2sdk/v2/api.py index efc33ff90..349153285 100644 --- a/b2sdk/v2/api.py +++ b/b2sdk/v2/api.py @@ -48,8 +48,8 @@ def get_bucket_by_id(self, bucket_id: str) -> v3.Bucket: except v3BucketIdNotFound as e: raise BucketIdNotFound(e.bucket_id) - # one should put "@limit_trace_arguments(only=('self', 'realm'))" here but logfury meta magic copies the appropriate - # attributes from base classes + # one could contemplate putting "@limit_trace_arguments(only=('self', 'realm'))" here but logfury meta magic copies + # the appropriate attributes from base classes def authorize_account(self, realm, application_key_id, application_key): return super().authorize_account( application_key_id=application_key_id, diff --git a/test/unit/api/test_api.py b/test/unit/api/test_api.py index 46889a88d..0cafb0456 100644 --- a/test/unit/api/test_api.py +++ b/test/unit/api/test_api.py @@ -55,6 +55,29 @@ def setUp(self): self.raw_api = self.api.session.raw_api (self.application_key_id, self.master_key) = self.raw_api.create_account() + @pytest.mark.apiver(from_ver=3) + def test_authorize_signature_v3_default_realm(self): + self.api.authorize_account( + self.application_key_id, + self.master_key, + ) + + @pytest.mark.apiver(from_ver=3) + def test_authorize_signature_v3_explicit_realm(self): + self.api.authorize_account( + self.application_key_id, + self.master_key, + 'production', + ) + + @pytest.mark.apiver(to_ver=2) + def test_authorize_signature_up_to_ver_2(self): + self.api.authorize_account( + 'production', + self.application_key_id, + self.master_key, + ) + def test_get_file_info(self): self._authorize_account() bucket = self.api.create_bucket('bucket1', 'allPrivate') From 96b18900e3f4a9e0d26db40629b54e5e0b47f4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Nowacki?= Date: Tue, 12 Dec 2023 12:22:45 +0100 Subject: [PATCH 5/5] changelog formatting fix --- changelog.d/+authorize_account.changed.md | 2 +- changelog.d/+make_tests_in_ci_verbose.infrastructure.md | 2 +- .../+run_windows_pypy_tests_on_nightly.infrastructure.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/changelog.d/+authorize_account.changed.md b/changelog.d/+authorize_account.changed.md index 49397c6c0..4ada0c76e 100644 --- a/changelog.d/+authorize_account.changed.md +++ b/changelog.d/+authorize_account.changed.md @@ -1 +1 @@ -Change v3.B2Api.authorize_account signature to make `realm` optional and `"production"` by default \ No newline at end of file +Change v3.B2Api.authorize_account signature to make `realm` optional and `"production"` by default. \ No newline at end of file diff --git a/changelog.d/+make_tests_in_ci_verbose.infrastructure.md b/changelog.d/+make_tests_in_ci_verbose.infrastructure.md index 3b56d7038..58575b342 100644 --- a/changelog.d/+make_tests_in_ci_verbose.infrastructure.md +++ b/changelog.d/+make_tests_in_ci_verbose.infrastructure.md @@ -1 +1 @@ -Add `-v` to pytest in CI \ No newline at end of file +Add `-v` to pytest in CI. \ No newline at end of file diff --git a/changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md b/changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md index fe7d8f12c..032ad9988 100644 --- a/changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md +++ b/changelog.d/+run_windows_pypy_tests_on_nightly.infrastructure.md @@ -1 +1 @@ -Run windows pypy3.9 tests on nightly builds \ No newline at end of file +Run windows pypy3.9 tests on nightly builds. \ No newline at end of file