From a135ffe9a57f1d94afcf8fe2009d571073a746fa Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Mon, 12 Sep 2022 17:27:40 +0300 Subject: [PATCH 1/9] Add server version control in SDK --- cvat-sdk/.gitignore | 14 +++--- cvat-sdk/cvat_sdk/core/client.py | 50 ++++++++++++++++++-- cvat-sdk/cvat_sdk/core/exceptions.py | 4 ++ cvat-sdk/gen/templates/requirements/base.txt | 3 +- tests/python/rest_api/test_server.py | 36 ++++++++++++++ tests/python/sdk/test_client.py | 36 +++++++++++++- 6 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 tests/python/rest_api/test_server.py diff --git a/cvat-sdk/.gitignore b/cvat-sdk/.gitignore index f27f78919cb0..d01a61d14490 100644 --- a/cvat-sdk/.gitignore +++ b/cvat-sdk/.gitignore @@ -70,10 +70,10 @@ schema/ .openapi-generator/ # Generated code -cvat_sdk/api_client/ -cvat_sdk/version.py -requirements/ -docs/ -setup.py -README.md -MANIFEST.in \ No newline at end of file +/cvat_sdk/api_client/ +/cvat_sdk/version.py +/requirements/ +/docs/ +/setup.py +/README.md +/MANIFEST.in \ No newline at end of file diff --git a/cvat-sdk/cvat_sdk/core/client.py b/cvat-sdk/cvat_sdk/core/client.py index cb8c42051c89..705f07ec7f3f 100644 --- a/cvat-sdk/cvat_sdk/core/client.py +++ b/cvat-sdk/cvat_sdk/core/client.py @@ -12,11 +12,12 @@ from typing import Any, Dict, Optional, Sequence, Tuple import attrs +import packaging.version as pv import urllib3 import urllib3.exceptions -from cvat_sdk.api_client import ApiClient, Configuration, models -from cvat_sdk.core.exceptions import InvalidHostException +from cvat_sdk.api_client import ApiClient, Configuration, exceptions, models +from cvat_sdk.core.exceptions import IncompatibleVersionException, InvalidHostException from cvat_sdk.core.helpers import expect_status from cvat_sdk.core.proxies.issues import CommentsRepo, IssuesRepo from cvat_sdk.core.proxies.jobs import JobsRepo @@ -24,12 +25,16 @@ from cvat_sdk.core.proxies.projects import ProjectsRepo from cvat_sdk.core.proxies.tasks import TasksRepo from cvat_sdk.core.proxies.users import UsersRepo +from cvat_sdk.version import VERSION @attrs.define class Config: status_check_period: float = 5 - """In seconds""" + """Operation status check period, in seconds""" + + allow_unsupported_server: bool = True + """Allow to use SDK with an unsupported server version. If disabled, raise an exception.""" class Client: @@ -45,6 +50,7 @@ def __init__( self.api_client = ApiClient(Configuration(host=self.api_map.host)) self.logger = logger or logging.getLogger(__name__) self.config = config or Config() + self.check_server_version() self._repos: Dict[str, Repo] = {} @@ -76,7 +82,7 @@ def _detect_schema(cls, base_url: str) -> str: for schema in cls.ALLOWED_SCHEMAS: with ApiClient(Configuration(host=f"{schema}://{base_url}")) as api_client: with suppress(urllib3.exceptions.RequestError): - (_, response) = api_client.schema_api.retrieve( + (_, response) = api_client.server_api.retrieve_about( _request_timeout=5, _parse_response=False, _check_status=False ) @@ -155,6 +161,42 @@ def wait_for_completion( return response + def check_server_version(self, fail_if_unsupported: Optional[bool] = None) -> None: + if fail_if_unsupported is None: + fail_if_unsupported = not self.config.allow_unsupported_server + + try: + server_version = self.get_server_version() + except exceptions.ApiException as e: + msg = ( + "Failed to retrieve server API version: %s. " + "Some SDK functions may not work properly with this server." + ) % (e,) + self.logger.warning(msg) + if fail_if_unsupported: + raise IncompatibleVersionException(msg) + return + + sdk_version = pv.Version(VERSION) + + # We only check base version match. Micro releases and fixes do not affect + # API compatibility in general. + if server_version.base_version != sdk_version.base_version: + msg = ( + "Server version '%s' is not compatible with SDK version '%s'. " + "Some SDK functions may not work properly with this server. " + "You can continue using this SDK, or you can " + "try to update with 'pip install cvat-sdk'." + ) % (server_version, sdk_version) + self.logger.warning(msg) + if fail_if_unsupported: + raise IncompatibleVersionException(msg) + + def get_server_version(self) -> pv.Version: + # TODO: allow to use this endpoint unauthorized + (about, _) = self.api_client.server_api.retrieve_about() + return pv.Version(about.version) + def _get_repo(self, key: str) -> Repo: _repo_map = { "tasks": TasksRepo, diff --git a/cvat-sdk/cvat_sdk/core/exceptions.py b/cvat-sdk/cvat_sdk/core/exceptions.py index c458bf02d102..b90a8fc18f54 100644 --- a/cvat-sdk/cvat_sdk/core/exceptions.py +++ b/cvat-sdk/cvat_sdk/core/exceptions.py @@ -9,3 +9,7 @@ class CvatSdkException(Exception): class InvalidHostException(CvatSdkException): """Indicates an invalid hostname error""" + + +class IncompatibleVersionException(CvatSdkException): + """Indicates server and SDK version mismatch""" diff --git a/cvat-sdk/gen/templates/requirements/base.txt b/cvat-sdk/gen/templates/requirements/base.txt index f22bae3b6fe0..ffc88d7e7eff 100644 --- a/cvat-sdk/gen/templates/requirements/base.txt +++ b/cvat-sdk/gen/templates/requirements/base.txt @@ -1,7 +1,8 @@ -r api_client.txt attrs >= 21.4.0 +packaging >= 21.3 Pillow >= 9.0.1 tqdm >= 4.64.0 tuspy == 0.2.5 # have it pinned, because SDK has lots of patched TUS code -typing_extensions >= 4.2.0 +typing_extensions >= 4.2.0 \ No newline at end of file diff --git a/tests/python/rest_api/test_server.py b/tests/python/rest_api/test_server.py new file mode 100644 index 000000000000..50d9d496b62a --- /dev/null +++ b/tests/python/rest_api/test_server.py @@ -0,0 +1,36 @@ +# Copyright (C) 2022 CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + + +from http import HTTPStatus +import pytest +from shared.utils.config import make_api_client + + +@pytest.mark.usefixtures('dontchangedb') +class TestGetServer: + def test_can_retrieve_about(self, admin_user: str): + with make_api_client(admin_user) as api_client: + (data, response) = api_client.server_api.retrieve_about() + + assert response.status == HTTPStatus.OK + assert data.version + + def test_can_retrieve_formats(self, admin_user: str): + with make_api_client(admin_user) as api_client: + (data, response) = api_client.server_api.retrieve_annotation_formats() + + assert response.status == HTTPStatus.OK + assert len(data.importers) != 0 + assert len(data.exporters) != 0 + + +@pytest.mark.usefixtures('dontchangedb') +class TestGetSchema: + def test_can_get_schema(self, admin_user: str): + with make_api_client(admin_user) as api_client: + (data, response) = api_client.schema_api.retrieve() + + assert response.status == HTTPStatus.OK + assert data diff --git a/tests/python/sdk/test_client.py b/tests/python/sdk/test_client.py index d36bf52bbb9b..15a3eef6571b 100644 --- a/tests/python/sdk/test_client.py +++ b/tests/python/sdk/test_client.py @@ -3,13 +3,15 @@ # SPDX-License-Identifier: MIT import io +from contextlib import ExitStack from logging import Logger from typing import Tuple +import packaging.version as pv import pytest from cvat_sdk import Client -from cvat_sdk.core.client import make_client -from cvat_sdk.core.exceptions import InvalidHostException +from cvat_sdk.core.client import Config, make_client +from cvat_sdk.core.exceptions import IncompatibleVersionException, InvalidHostException from cvat_sdk.exceptions import ApiException from shared.utils.config import BASE_URL, USER_PASS @@ -48,6 +50,13 @@ def test_can_logout(self): assert not self.client.has_credentials() + def test_can_get_server_version(self): + self.client.login((self.user, USER_PASS)) + + version = self.client.get_server_version() + + assert (version.major, version.minor) >= (2, 0) + def test_can_detect_server_schema_if_not_provided(): host, port = BASE_URL.split("://", maxsplit=1)[1].rsplit(":", maxsplit=1) @@ -69,3 +78,26 @@ def test_can_reject_invalid_server_schema(): make_client(host="ftp://" + host, port=int(port) + 1) assert capture.match(r"Invalid url schema 'ftp'") + + +@pytest.mark.parametrize("raise_exception", (True, False)) +def test_can_warn_on_mismatching_server_version( + fxt_logger: Tuple[Logger, io.StringIO], monkeypatch, raise_exception: bool +): + logger, logger_stream = fxt_logger + + def mocked_version(_): + return pv.Version("0") + + monkeypatch.setattr(Client, "get_server_version", mocked_version) + + config = Config() + + with ExitStack() as es: + if raise_exception: + es.enter_context(pytest.raises(IncompatibleVersionException)) + config.allow_unsupported_server = False + + Client(url=BASE_URL, logger=logger, config=config) + + assert "Server version '0' is not compatible with SDK version" in logger_stream.getvalue() From 40a1d18183399797dc0f6ad1cf8c4fa7b338c59e Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Mon, 12 Sep 2022 19:01:50 +0300 Subject: [PATCH 2/9] Sync server schema version with server version --- cvat/settings/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cvat/settings/base.py b/cvat/settings/base.py index 9cac8971d2fb..92516fc308a5 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -23,6 +23,7 @@ import mimetypes from corsheaders.defaults import default_headers from distutils.util import strtobool +from cvat import __version__ mimetypes.add_type("application/wasm", ".wasm", True) @@ -510,7 +511,7 @@ def add_ssh_keys(): # Statically set schema version. May also be an empty string. When used together with # view versioning, will become '0.0.0 (v2)' for 'v2' versioned requests. # Set VERSION to None if only the request version should be rendered. - 'VERSION': '2.1.0', + 'VERSION': __version__, 'CONTACT': { 'name': 'CVAT.ai team', 'url': 'https://github.com/cvat-ai/cvat', From 40552d4fc2f6f045d674e6d840048c0687f77ad0 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Mon, 12 Sep 2022 19:31:04 +0300 Subject: [PATCH 3/9] Allow unauthorized access to api/about/, api/docs/, api/swagger, api/schema --- cvat-sdk/cvat_sdk/core/client.py | 4 +++- cvat/apps/engine/urls.py | 14 +++++++++++--- cvat/apps/engine/views.py | 4 +++- tests/python/rest_api/test_server.py | 8 ++++---- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/client.py b/cvat-sdk/cvat_sdk/core/client.py index 705f07ec7f3f..27cdf75f7b3c 100644 --- a/cvat-sdk/cvat_sdk/core/client.py +++ b/cvat-sdk/cvat_sdk/core/client.py @@ -86,7 +86,9 @@ def _detect_schema(cls, base_url: str) -> str: _request_timeout=5, _parse_response=False, _check_status=False ) - if response.status == 401: + if response.status in [200, 401]: + # Versions prior to 2.2.0 respond with unauthorized + # 2.2.0 allows unauthorized access return schema raise InvalidHostException( diff --git a/cvat/apps/engine/urls.py b/cvat/apps/engine/urls.py index 7edbd07b7ca5..aa2537a04c77 100644 --- a/cvat/apps/engine/urls.py +++ b/cvat/apps/engine/urls.py @@ -30,9 +30,17 @@ query_string=True)), # documentation for API - path('api/schema/', SpectacularAPIView.as_view(), name='schema'), - path('api/swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger'), - path('api/docs/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), + path('api/schema/', SpectacularAPIView.as_view( + permission_classes=[] # This endpoint is available for everyone + ), name='schema'), + path('api/swagger/', SpectacularSwaggerView.as_view( + url_name='schema', + permission_classes=[] # This endpoint is available for everyone + ), name='swagger'), + path('api/docs/', SpectacularRedocView.as_view( + url_name='schema', + permission_classes=[] # This endpoint is available for everyone + ), name='redoc'), # entry point for API path('api/', include('cvat.apps.iam.urls')), diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 007e6f0453b5..0ad477da5b89 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -93,7 +93,9 @@ def get_serializer(self, *args, **kwargs): responses={ '200': AboutSerializer, }) - @action(detail=False, methods=['GET'], serializer_class=AboutSerializer) + @action(detail=False, methods=['GET'], serializer_class=AboutSerializer, + permission_classes=[] # This endpoint is available for everyone + ) def about(request): from cvat import __version__ as cvat_version about = { diff --git a/tests/python/rest_api/test_server.py b/tests/python/rest_api/test_server.py index 50d9d496b62a..d677f21d91f3 100644 --- a/tests/python/rest_api/test_server.py +++ b/tests/python/rest_api/test_server.py @@ -10,8 +10,8 @@ @pytest.mark.usefixtures('dontchangedb') class TestGetServer: - def test_can_retrieve_about(self, admin_user: str): - with make_api_client(admin_user) as api_client: + def test_can_retrieve_about_unauthorized(self): + with make_api_client(user=None, password=None) as api_client: (data, response) = api_client.server_api.retrieve_about() assert response.status == HTTPStatus.OK @@ -28,8 +28,8 @@ def test_can_retrieve_formats(self, admin_user: str): @pytest.mark.usefixtures('dontchangedb') class TestGetSchema: - def test_can_get_schema(self, admin_user: str): - with make_api_client(admin_user) as api_client: + def test_can_get_schema_unauthorized(self): + with make_api_client(user=None, password=None) as api_client: (data, response) = api_client.schema_api.retrieve() assert response.status == HTTPStatus.OK From e07d9ba460188f0c1171f0382a5c1b1a6824aa5d Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Mon, 12 Sep 2022 19:31:31 +0300 Subject: [PATCH 4/9] Add test for cli notification about version --- tests/python/cli/test_cli.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/python/cli/test_cli.py b/tests/python/cli/test_cli.py index a2d9db5074a5..f2624fc469d0 100644 --- a/tests/python/cli/test_cli.py +++ b/tests/python/cli/test_cli.py @@ -7,8 +7,9 @@ import os from pathlib import Path +import packaging.version as pv import pytest -from cvat_sdk import make_client +from cvat_sdk import Client, make_client from cvat_sdk.api_client import exceptions from cvat_sdk.core.proxies.tasks import ResourceType, Task from PIL import Image @@ -188,3 +189,14 @@ def test_can_create_from_backup(self, fxt_new_task: Task, fxt_backup_file: Path) assert task_id assert task_id != fxt_new_task.id assert self.client.tasks.retrieve(task_id).size == fxt_new_task.size + + def test_can_warn_on_mismatching_server_version(self, monkeypatch, caplog): + def mocked_version(_): + return pv.Version("0") + + # We don't actually run a separate process in the tests here, so it works + monkeypatch.setattr(Client, "get_server_version", mocked_version) + + self.run_cli("ls") + + assert "Server version '0' is not compatible with SDK version" in caplog.text From 2aa8ded81bc15157ef54a98a6300c77f9fa9fce3 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Fri, 16 Sep 2022 13:46:03 +0300 Subject: [PATCH 5/9] Extend the list of supported versions in CLI --- cvat-sdk/cvat_sdk/core/client.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/client.py b/cvat-sdk/cvat_sdk/core/client.py index 6b6f9f7c6b4b..d91c8888ff67 100644 --- a/cvat-sdk/cvat_sdk/core/client.py +++ b/cvat-sdk/cvat_sdk/core/client.py @@ -45,6 +45,13 @@ class Client: Manages session and configuration. """ + SUPPORTED_SERVER_VERSIONS = ( + pv.Version("2.0"), + pv.Version("2.1"), + pv.Version("2.2"), + pv.Version("2.3"), + ) + def __init__( self, url: str, *, logger: Optional[logging.Logger] = None, config: Optional[Config] = None ): @@ -92,8 +99,8 @@ def _detect_schema(cls, base_url: str) -> str: ) if response.status in [200, 401]: - # Versions prior to 2.2.0 respond with unauthorized - # 2.2.0 allows unauthorized access + # Versions prior to 2.3.0 respond with unauthorized + # 2.3.0 allows unauthorized access return schema raise InvalidHostException( @@ -188,7 +195,9 @@ def check_server_version(self, fail_if_unsupported: Optional[bool] = None) -> No # We only check base version match. Micro releases and fixes do not affect # API compatibility in general. - if server_version.base_version != sdk_version.base_version: + if all( + server_version.base_version != sv.base_version for sv in self.SUPPORTED_SERVER_VERSIONS + ): msg = ( "Server version '%s' is not compatible with SDK version '%s'. " "Some SDK functions may not work properly with this server. " From 478282e0056605a9ce2ae556a71e4349a8765cbb Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Tue, 20 Sep 2022 13:11:09 +0300 Subject: [PATCH 6/9] Fix url building --- cvat-cli/src/cvat_cli/__main__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cvat-cli/src/cvat_cli/__main__.py b/cvat-cli/src/cvat_cli/__main__.py index 63cb31a0b3a0..2530169cf7de 100755 --- a/cvat-cli/src/cvat_cli/__main__.py +++ b/cvat-cli/src/cvat_cli/__main__.py @@ -33,8 +33,12 @@ def configure_logger(level): def build_client(parsed_args: SimpleNamespace, logger: logging.Logger) -> Client: config = Config(verify_ssl=not parsed_args.insecure) + url = parsed_args.server_host + if parsed_args.server_port: + url += ':{parsed_args.server_port}' + return Client( - url="{host}:{port}".format(host=parsed_args.server_host, port=parsed_args.server_port), + url=url, logger=logger, config=config, ) From 20d18a3553fb6e9724267f50c9cbed8a34e10d66 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Tue, 20 Sep 2022 14:42:14 +0300 Subject: [PATCH 7/9] Improve schema error message --- cvat-sdk/cvat_sdk/core/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat-sdk/cvat_sdk/core/client.py b/cvat-sdk/cvat_sdk/core/client.py index d91c8888ff67..06121030867a 100644 --- a/cvat-sdk/cvat_sdk/core/client.py +++ b/cvat-sdk/cvat_sdk/core/client.py @@ -105,7 +105,7 @@ def _detect_schema(cls, base_url: str) -> str: raise InvalidHostException( "Failed to detect host schema automatically, please check " - "the server url and try to specify schema explicitly" + "the server url and try to specify 'https://' or 'http://' explicitly" ) def __enter__(self): From e2a5e7dc224f342af2255dd2988bdf50727f482b Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Tue, 20 Sep 2022 14:43:43 +0300 Subject: [PATCH 8/9] Improve version check behaviour --- cvat-cli/src/cvat_cli/__main__.py | 3 ++- cvat-cli/src/cvat_cli/cli.py | 2 ++ cvat-sdk/cvat_sdk/core/client.py | 15 ++++++++--- tests/python/sdk/test_client.py | 45 ++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/cvat-cli/src/cvat_cli/__main__.py b/cvat-cli/src/cvat_cli/__main__.py index 2530169cf7de..ce32b832fdde 100755 --- a/cvat-cli/src/cvat_cli/__main__.py +++ b/cvat-cli/src/cvat_cli/__main__.py @@ -35,12 +35,13 @@ def build_client(parsed_args: SimpleNamespace, logger: logging.Logger) -> Client url = parsed_args.server_host if parsed_args.server_port: - url += ':{parsed_args.server_port}' + url += f":{parsed_args.server_port}" return Client( url=url, logger=logger, config=config, + check_server_version=False, # version is checked after auth to support versions < 2.3 ) diff --git a/cvat-cli/src/cvat_cli/cli.py b/cvat-cli/src/cvat_cli/cli.py index 4609f95491ab..00122341cf58 100644 --- a/cvat-cli/src/cvat_cli/cli.py +++ b/cvat-cli/src/cvat_cli/cli.py @@ -23,6 +23,8 @@ def __init__(self, client: Client, credentials: Tuple[str, str]): self.client.login(credentials) + self.client.check_server_version(fail_if_unsupported=False) + def tasks_list(self, *, use_json_output: bool = False, **kwargs): """List all tasks in either basic or JSON format.""" results = self.client.tasks.list(return_json=use_json_output, **kwargs) diff --git a/cvat-sdk/cvat_sdk/core/client.py b/cvat-sdk/cvat_sdk/core/client.py index 06121030867a..a60ec63767af 100644 --- a/cvat-sdk/cvat_sdk/core/client.py +++ b/cvat-sdk/cvat_sdk/core/client.py @@ -53,8 +53,13 @@ class Client: ) def __init__( - self, url: str, *, logger: Optional[logging.Logger] = None, config: Optional[Config] = None - ): + self, + url: str, + *, + logger: Optional[logging.Logger] = None, + config: Optional[Config] = None, + check_server_version: bool = True, + ) -> None: url = self._validate_and_prepare_url(url) self.logger = logger or logging.getLogger(__name__) self.config = config or Config() @@ -62,7 +67,9 @@ def __init__( self.api_client = ApiClient( Configuration(host=self.api_map.host, verify_ssl=self.config.verify_ssl) ) - self.check_server_version() + + if check_server_version: + self.check_server_version() self._repos: Dict[str, Repo] = {} @@ -99,7 +106,7 @@ def _detect_schema(cls, base_url: str) -> str: ) if response.status in [200, 401]: - # Versions prior to 2.3.0 respond with unauthorized + # Server versions prior to 2.3.0 respond with unauthorized # 2.3.0 allows unauthorized access return schema diff --git a/tests/python/sdk/test_client.py b/tests/python/sdk/test_client.py index 2946e04be635..7fdf70eee650 100644 --- a/tests/python/sdk/test_client.py +++ b/tests/python/sdk/test_client.py @@ -95,14 +95,57 @@ def mocked_version(_): with ExitStack() as es: if raise_exception: - es.enter_context(pytest.raises(IncompatibleVersionException)) config.allow_unsupported_server = False + es.enter_context(pytest.raises(IncompatibleVersionException)) Client(url=BASE_URL, logger=logger, config=config) assert "Server version '0' is not compatible with SDK version" in logger_stream.getvalue() +@pytest.mark.parametrize("do_check", (True, False)) +def test_can_check_server_version_in_ctor( + fxt_logger: Tuple[Logger, io.StringIO], monkeypatch, do_check: bool +): + logger, logger_stream = fxt_logger + + def mocked_version(_): + return pv.Version("0") + + monkeypatch.setattr(Client, "get_server_version", mocked_version) + + config = Config() + config.allow_unsupported_server = False + + with ExitStack() as es: + if do_check: + es.enter_context(pytest.raises(IncompatibleVersionException)) + + Client(url=BASE_URL, logger=logger, config=config, check_server_version=do_check) + + assert ( + "Server version '0' is not compatible with SDK version" in logger_stream.getvalue() + ) == do_check + + +def test_can_check_server_version_in_method(fxt_logger: Tuple[Logger, io.StringIO], monkeypatch): + logger, logger_stream = fxt_logger + + def mocked_version(_): + return pv.Version("0") + + monkeypatch.setattr(Client, "get_server_version", mocked_version) + + config = Config() + config.allow_unsupported_server = False + client = Client(url=BASE_URL, logger=logger, config=config, check_server_version=False) + + with client, pytest.raises(IncompatibleVersionException): + client.check_server_version() + + assert "Server version '0' is not compatible with SDK version" in logger_stream.getvalue() + + @pytest.mark.parametrize("verify", [True, False]) def test_can_control_ssl_verification_with_config(verify: bool): config = Config(verify_ssl=verify) From ea4bde48312c4435955ef3cb100043cf888c98b0 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Wed, 28 Sep 2022 14:29:38 +0500 Subject: [PATCH 9/9] Fix test --- cvat/apps/engine/tests/test_rest_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index 43b82ab405c8..a503c811ea46 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -504,7 +504,7 @@ def test_api_v2_server_about_user(self): def test_api_v2_server_about_no_auth(self): response = self._run_api_v2_server_about(None) - self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(response.status_code, status.HTTP_200_OK) def test_api_server_about_versions_admin(self): for version in settings.REST_FRAMEWORK['ALLOWED_VERSIONS']: