From 239d04c979ffc31a22ef4b88f8a328581ec84d40 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:28:28 +0200 Subject: [PATCH 01/16] cleanup --- clients/python/test/test_osparc/conftest.py | 2 +- clients/python/test/test_osparc/test_apis.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/clients/python/test/test_osparc/conftest.py b/clients/python/test/test_osparc/conftest.py index 1b26daea..4c3ac2aa 100644 --- a/clients/python/test/test_osparc/conftest.py +++ b/clients/python/test/test_osparc/conftest.py @@ -14,5 +14,5 @@ def cfg() -> Iterator[osparc.Configuration]: @pytest.fixture -def enable_dev_mode(monkeypatch): +def dev_mode_enabled(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setenv("OSPARC_DEV_FEATURES_ENABLED", "1") diff --git a/clients/python/test/test_osparc/test_apis.py b/clients/python/test/test_osparc/test_apis.py index 011a5ab3..7b55c85e 100644 --- a/clients/python/test/test_osparc/test_apis.py +++ b/clients/python/test/test_osparc/test_apis.py @@ -2,7 +2,9 @@ from typing import Callable import pytest +from faker import Faker from osparc import SolversApi, StudiesApi +from pytest_mock import MockerFixture @pytest.fixture @@ -12,12 +14,16 @@ def _(enable: bool): monkeypatch.setenv("OSPARC_STUDY_ID", f"{faker.uuid4()}") monkeypatch.setenv("OSPARC_NODE_ID", f"{faker.uuid4()}") - yield _ + return _ @pytest.mark.parametrize("parent_env", [True, False]) def test_create_jobs_parent_headers( - mocker, faker, create_parent_env, enable_dev_mode, parent_env: bool + mocker: MockerFixture, + faker: Faker, + create_parent_env: Callable, + dev_mode_enabled: None, + parent_env: bool, ): create_parent_env(parent_env) From 77838c8547f93ea51f2c07c7c4c03b09c2899254 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:36:57 +0200 Subject: [PATCH 02/16] overrides Config with new defaults --- clients/python/client/osparc/__init__.py | 36 +++++++++---------- .../python/client/osparc/_configuration.py | 36 +++++++++++++++++++ clients/python/client/osparc/_http_client.py | 2 +- 3 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 clients/python/client/osparc/_configuration.py diff --git a/clients/python/client/osparc/__init__.py b/clients/python/client/osparc/__init__.py index 0bf05f87..7889f3a4 100644 --- a/clients/python/client/osparc/__init__.py +++ b/clients/python/client/osparc/__init__.py @@ -10,7 +10,6 @@ ApiTypeError, ApiValueError, BodyUploadFileV0FilesContentPut, - Configuration, ErrorGet, File, Groups, @@ -44,6 +43,7 @@ from ._solvers_api import SolversApi from ._studies_api import StudiesApi from ._utils import dev_features_enabled +from ._configuration import Configuration _PYTHON_VERSION_DEPRECATED = Version("3.6.0") _PYTHON_VERSION_SUPPORTED = Version("3.8.0") @@ -81,13 +81,16 @@ __all__: Tuple[str, ...] = tuple(dev_features) + ( "__version__", - "FilesApi", - "MetaApi", - "SolversApi", - "StudiesApi", - "UsersApi", + "ApiClient", + "ApiException", + "ApiKeyError", + "ApiTypeError", + "ApiValueError", "BodyUploadFileV0FilesContentPut", + "Configuration", + "ErrorGet", "File", + "FilesApi", "Groups", "HTTPValidationError", "Job", @@ -95,23 +98,20 @@ "JobOutputs", "JobStatus", "Meta", + "MetaApi", + "OnePageSolverPort", + "openapi", + "OpenApiException", "Profile", "ProfileUpdate", + "RequestError", "Solver", + "SolverPort", + "SolversApi", + "StudiesApi", "TaskStates", "UserRoleEnum", + "UsersApi", "UsersGroup", "ValidationError", - "ApiClient", - "Configuration", - "OpenApiException", - "ApiTypeError", - "ApiValueError", - "ApiKeyError", - "ApiException", - "OnePageSolverPort", - "SolverPort", - "ErrorGet", - "openapi", - "RequestError", ) # type: ignore diff --git a/clients/python/client/osparc/_configuration.py b/clients/python/client/osparc/_configuration.py new file mode 100644 index 00000000..a7746126 --- /dev/null +++ b/clients/python/client/osparc/_configuration.py @@ -0,0 +1,36 @@ +from typing import Set +from osparc_client.configuration import Configuration as _Configuration +import os + +class Configuration(_Configuration): + def __init__( + self, + host=None, + api_key=None, + api_key_prefix=None, + username=None, + password=None, + signing_info=None, + *, + retry_max_count: int = 4, + retry_methods: Set[str] = ..., + retry_status_codes: Set[int] = ..., + retry_backoff_factor=4 + ): + # SEE https://github.com/ITISFoundation/osparc-simcore/issues/5925 + host = host or os.environ.get("OSPARC_API_BASE_URL", "https://api.osparc.io") + username = username or os.environ.get("OSPARC_API_KEY") + password = password or os.environ.get("OSPARC_API_SECRET") + + super().__init__( + host, + api_key, + api_key_prefix, + username, + password, + signing_info, + retry_max_count=retry_max_count, + retry_methods=retry_methods, + retry_status_codes=retry_status_codes, + retry_backoff_factor=retry_backoff_factor, + ) diff --git a/clients/python/client/osparc/_http_client.py b/clients/python/client/osparc/_http_client.py index 98b8c6a6..376cf19f 100644 --- a/clients/python/client/osparc/_http_client.py +++ b/clients/python/client/osparc/_http_client.py @@ -4,7 +4,7 @@ import httpx import tenacity -from osparc_client import Configuration +from ._configuration import Configuration _RETRY_AFTER_STATUS_CODES: Set[int] = {429, 503} From da8e3882dd7e2787d9a7a08218a2f6e364b57989 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:59:37 +0200 Subject: [PATCH 03/16] testing config --- .../python/client/osparc/_configuration.py | 7 +++- clients/python/test/test_osparc/test_apis.py | 41 ++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/clients/python/client/osparc/_configuration.py b/clients/python/client/osparc/_configuration.py index a7746126..be57579f 100644 --- a/clients/python/client/osparc/_configuration.py +++ b/clients/python/client/osparc/_configuration.py @@ -1,6 +1,8 @@ +import os from typing import Set + from osparc_client.configuration import Configuration as _Configuration -import os +import osparc_client class Configuration(_Configuration): def __init__( @@ -34,3 +36,6 @@ def __init__( retry_status_codes=retry_status_codes, retry_backoff_factor=retry_backoff_factor, ) + + +osparc_client.Configuration = Configuration \ No newline at end of file diff --git a/clients/python/test/test_osparc/test_apis.py b/clients/python/test/test_osparc/test_apis.py index 7b55c85e..bc940e32 100644 --- a/clients/python/test/test_osparc/test_apis.py +++ b/clients/python/test/test_osparc/test_apis.py @@ -3,12 +3,14 @@ import pytest from faker import Faker -from osparc import SolversApi, StudiesApi +from osparc import Configuration, SolversApi, StudiesApi from pytest_mock import MockerFixture @pytest.fixture -def create_parent_env(monkeypatch, faker) -> Callable[[bool], None]: +def create_parent_env( + monkeypatch: pytest.MonkeyPatch, faker: Faker +) -> Callable[[bool], None]: def _(enable: bool): if enable: monkeypatch.setenv("OSPARC_STUDY_ID", f"{faker.uuid4()}") @@ -57,3 +59,38 @@ def check_headers(**kwargs): studies_api = StudiesApi() studies_api.create_study_job(study_id=faker.uuid4(), job_inputs={}) studies_api.clone_study(study_id=faker.uuid4()) + +from osparc import ApiClient + + +def test_configuration_constructor(monkeypatch: pytest.MonkeyPatch): + + with monkeypatch.context() as patch: + patch.delenv("OSPARC_API_BASE_URL", raising=False) + patch.delenv("OSPARC_API_KEY", raising=False) + patch.delenv("OSPARC_API_SECRET", raising=False) + + config = Configuration() + assert config.host == "https://api.osparc.io" + assert config.username is None + assert config.password is None + + with monkeypatch.context() as patch: + patch.setenv("OSPARC_API_BASE_URL", "https://api.foo.com") + patch.setenv("OSPARC_API_KEY", "key") + patch.setenv("OSPARC_API_SECRET", "secret") + + config = Configuration() + assert config.host == "https://api.foo.com" + assert config.username == "key" + assert config.password == "secret" + + api = ApiClient() + assert api.configuration == config + + config = Configuration(username="foo") + assert config.host == "https://api.foo.com" + assert config.username == "foo" + assert config.password == "secret" + + From b4a2e37ae1245c60aedcb175d0a43931d668a722 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:02:28 +0200 Subject: [PATCH 04/16] upgrades pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c619604c..226cb491 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ # See https://pre-commit.com/hooks.html for more hooks exclude: "^.venv$|^.cache$|^.pytest_cache$" default_language_version: - python: python3.9 + python: python3.10 repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 From ca74b42193237da0044bd93855e4107400697a30 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:14:02 +0200 Subject: [PATCH 05/16] mv pytest.ini --- clients/python/test/{test_osparc => }/pytest.ini | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename clients/python/test/{test_osparc => }/pytest.ini (100%) diff --git a/clients/python/test/test_osparc/pytest.ini b/clients/python/test/pytest.ini similarity index 100% rename from clients/python/test/test_osparc/pytest.ini rename to clients/python/test/pytest.ini From 129abe80ff10665632089d9ca9b2842b277b5b60 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 19 Jun 2024 17:29:16 +0200 Subject: [PATCH 06/16] monkey patch --- .../python/client/osparc/_configuration.py | 71 ++++++++++--------- clients/python/test/test_osparc/test_apis.py | 11 ++- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/clients/python/client/osparc/_configuration.py b/clients/python/client/osparc/_configuration.py index be57579f..f529f491 100644 --- a/clients/python/client/osparc/_configuration.py +++ b/clients/python/client/osparc/_configuration.py @@ -1,41 +1,44 @@ import os from typing import Set -from osparc_client.configuration import Configuration as _Configuration -import osparc_client +from osparc_client.configuration import Configuration + +# Monkey patches __init__ +original_init = Configuration.__init__ -class Configuration(_Configuration): - def __init__( - self, - host=None, - api_key=None, - api_key_prefix=None, - username=None, - password=None, - signing_info=None, - *, - retry_max_count: int = 4, - retry_methods: Set[str] = ..., - retry_status_codes: Set[int] = ..., - retry_backoff_factor=4 - ): - # SEE https://github.com/ITISFoundation/osparc-simcore/issues/5925 - host = host or os.environ.get("OSPARC_API_BASE_URL", "https://api.osparc.io") - username = username or os.environ.get("OSPARC_API_KEY") - password = password or os.environ.get("OSPARC_API_SECRET") - super().__init__( - host, - api_key, - api_key_prefix, - username, - password, - signing_info, - retry_max_count=retry_max_count, - retry_methods=retry_methods, - retry_status_codes=retry_status_codes, - retry_backoff_factor=retry_backoff_factor, - ) +def new_init( + self, + host=None, + api_key=None, + api_key_prefix=None, + username=None, + password=None, + signing_info=None, + *, + retry_max_count: int = 4, + retry_methods: Set[str] = ..., + retry_status_codes: Set[int] = ..., + retry_backoff_factor=4 +): + # SEE https://github.com/ITISFoundation/osparc-simcore/issues/5925 + host = host or os.environ.get("OSPARC_API_BASE_URL", "https://api.osparc.io") + username = username or os.environ.get("OSPARC_API_KEY") + password = password or os.environ.get("OSPARC_API_SECRET") + + original_init( + self, + host, + api_key, + api_key_prefix, + username, + password, + signing_info, + retry_max_count=retry_max_count, + retry_methods=retry_methods, + retry_status_codes=retry_status_codes, + retry_backoff_factor=retry_backoff_factor, + ) -osparc_client.Configuration = Configuration \ No newline at end of file +Configuration.__init__ = new_init diff --git a/clients/python/test/test_osparc/test_apis.py b/clients/python/test/test_osparc/test_apis.py index bc940e32..04dbe166 100644 --- a/clients/python/test/test_osparc/test_apis.py +++ b/clients/python/test/test_osparc/test_apis.py @@ -3,7 +3,7 @@ import pytest from faker import Faker -from osparc import Configuration, SolversApi, StudiesApi +from osparc import ApiClient, Configuration, SolversApi, StudiesApi from pytest_mock import MockerFixture @@ -60,11 +60,8 @@ def check_headers(**kwargs): studies_api.create_study_job(study_id=faker.uuid4(), job_inputs={}) studies_api.clone_study(study_id=faker.uuid4()) -from osparc import ApiClient - def test_configuration_constructor(monkeypatch: pytest.MonkeyPatch): - with monkeypatch.context() as patch: patch.delenv("OSPARC_API_BASE_URL", raising=False) patch.delenv("OSPARC_API_KEY", raising=False) @@ -86,11 +83,11 @@ def test_configuration_constructor(monkeypatch: pytest.MonkeyPatch): assert config.password == "secret" api = ApiClient() - assert api.configuration == config + assert api.configuration.host == config.host + assert api.configuration.username == config.username + assert api.configuration.password == config.password config = Configuration(username="foo") assert config.host == "https://api.foo.com" assert config.username == "foo" assert config.password == "secret" - - From 132a4f8a09c632aeeea86157fc731c88e084dcbd Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Mon, 23 Oct 2023 11:33:27 +0200 Subject: [PATCH 07/16] update workflow before publishing python package fix dependency issue and bump version point to website in project description fix broken dependency improve doc add github token to download artifacts ensure only read-access @wvangeit yet another attempt at downloading artifacts make sure to use repo that ran the trigger wf another attempt at fixing change owner allow publishing to testpypi also when pr minor change revert minor (but breaking) change minor fix add debug messages another debug message hopefully the final version final fix minor fix move master and tag to individual jobs add debug messages add python script for determining semantic version minor changes minor changes improve error handling and add version file to artifacts check if release minor fix ensure to enter venv also when tagging source venv in publishin workflow ensure only master add script for testing 'pure' semver adapt workflows to new python script minor change attempt to evaluate expressions correctly several fixes to fix tests ensure repo is checked out in publish workflow several small fixes cleanup debug minor cleanup mionr changes add debug message minor change minor change yet another try minor change minor change minor change mionr change minor changes correct workflow run id cosmetic change avoid using gh change to a single job for publishing minor cleanup swap loops in clean up jobs correction get correct versions of github workflow files update a couple of other files update a few more tests update yet another file yet another file From 2995354f6ba29e4b05a6318013166056a4de58b6 Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 13:16:55 +0200 Subject: [PATCH 08/16] wrap api_client --- clients/python/client/osparc/__init__.py | 4 +-- clients/python/client/osparc/_api_client.py | 33 +++++++++++++++++++++ clients/python/client/osparc/_models.py | 16 ++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 clients/python/client/osparc/_api_client.py diff --git a/clients/python/client/osparc/__init__.py b/clients/python/client/osparc/__init__.py index 7889f3a4..59d57a8b 100644 --- a/clients/python/client/osparc/__init__.py +++ b/clients/python/client/osparc/__init__.py @@ -4,7 +4,6 @@ import nest_asyncio from osparc_client import ( # APIs; API client; models - ApiClient, ApiException, ApiKeyError, ApiTypeError, @@ -37,13 +36,14 @@ ) from packaging.version import Version +from ._api_client import ApiClient +from ._configuration import Configuration from ._exceptions import RequestError, VisibleDeprecationWarning from ._files_api import FilesApi from ._info import openapi from ._solvers_api import SolversApi from ._studies_api import StudiesApi from ._utils import dev_features_enabled -from ._configuration import Configuration _PYTHON_VERSION_DEPRECATED = Version("3.6.0") _PYTHON_VERSION_SUPPORTED = Version("3.8.0") diff --git a/clients/python/client/osparc/_api_client.py b/clients/python/client/osparc/_api_client.py new file mode 100644 index 00000000..c477bb28 --- /dev/null +++ b/clients/python/client/osparc/_api_client.py @@ -0,0 +1,33 @@ +from osparc_client import ApiClient as _ApiClient +from osparc_client import Configuration +from pydantic import ValidationError + +from ._models import ConfigurationModel + + +class ApiClient(_ApiClient): + def __init__( + self, + configuration=None, + header_name=None, + header_value=None, + cookie=None, + pool_threads=1, + ): + if configuration is None: + try: + env_vars = ConfigurationModel() + configuration = Configuration( + host=f"{env_vars.OSPARC_API_HOST}", + username=env_vars.OSPARC_API_KEY, + password=env_vars.OSPARC_API_SECRET, + ) + except ValidationError as exc: + raise RuntimeError( + "Could not initialize configuration from environment. " + "If your osparc host, key and secret are not exposed as " + "environment variables you must construct the " + "Configuration object explicitly" + ) from exc + + super().__init__(configuration, header_name, header_value, cookie, pool_threads) diff --git a/clients/python/client/osparc/_models.py b/clients/python/client/osparc/_models.py index 4e5ea3cc..b5266f28 100644 --- a/clients/python/client/osparc/_models.py +++ b/clients/python/client/osparc/_models.py @@ -1,7 +1,7 @@ from typing import Optional from uuid import UUID -from pydantic import Field, field_validator +from pydantic import AnyHttpUrl, Field, field_validator from pydantic_settings import BaseSettings @@ -18,7 +18,19 @@ class ParentProjectInfo(BaseSettings): @field_validator("x_simcore_parent_project_uuid", "x_simcore_parent_node_id") @classmethod - def _validate_uuids(cls, v: Optional[str]) -> str: + def _validate_uuids(cls, v: Optional[str]) -> Optional[str]: if v is not None: _ = UUID(v) return v + + +class ConfigurationModel(BaseSettings): + """Model for capturing env vars which should go into the Configuration""" + + OSPARC_API_HOST: AnyHttpUrl = Field( + default=..., + description="OSPARC api url", + examples=["https://api.osparc-master.speag.com/"], + ) + OSPARC_API_KEY: str = Field(default=..., description="OSPARC api key") + OSPARC_API_SECRET: str = Field(default=..., description="OSPARC api secret") From 6f1e38c28c29911293b46289b48738360e5a8feb Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 13:18:11 +0200 Subject: [PATCH 09/16] add type --- clients/python/client/osparc/_api_client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clients/python/client/osparc/_api_client.py b/clients/python/client/osparc/_api_client.py index c477bb28..e2d40f67 100644 --- a/clients/python/client/osparc/_api_client.py +++ b/clients/python/client/osparc/_api_client.py @@ -1,3 +1,5 @@ +from typing import Optional + from osparc_client import ApiClient as _ApiClient from osparc_client import Configuration from pydantic import ValidationError @@ -8,7 +10,7 @@ class ApiClient(_ApiClient): def __init__( self, - configuration=None, + configuration: Optional[Configuration] = None, header_name=None, header_value=None, cookie=None, From e3c83aa4bccf632d1a8de13ce1715fb71bfd69ea Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 13:20:20 +0200 Subject: [PATCH 10/16] remove _configuration.py --- .../python/client/osparc/_configuration.py | 44 ------------------- 1 file changed, 44 deletions(-) delete mode 100644 clients/python/client/osparc/_configuration.py diff --git a/clients/python/client/osparc/_configuration.py b/clients/python/client/osparc/_configuration.py deleted file mode 100644 index f529f491..00000000 --- a/clients/python/client/osparc/_configuration.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -from typing import Set - -from osparc_client.configuration import Configuration - -# Monkey patches __init__ -original_init = Configuration.__init__ - - -def new_init( - self, - host=None, - api_key=None, - api_key_prefix=None, - username=None, - password=None, - signing_info=None, - *, - retry_max_count: int = 4, - retry_methods: Set[str] = ..., - retry_status_codes: Set[int] = ..., - retry_backoff_factor=4 -): - # SEE https://github.com/ITISFoundation/osparc-simcore/issues/5925 - host = host or os.environ.get("OSPARC_API_BASE_URL", "https://api.osparc.io") - username = username or os.environ.get("OSPARC_API_KEY") - password = password or os.environ.get("OSPARC_API_SECRET") - - original_init( - self, - host, - api_key, - api_key_prefix, - username, - password, - signing_info, - retry_max_count=retry_max_count, - retry_methods=retry_methods, - retry_status_codes=retry_status_codes, - retry_backoff_factor=retry_backoff_factor, - ) - - -Configuration.__init__ = new_init From 8097e26ff8c20d18e38c0f958f9967189e7ab243 Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 13:49:05 +0200 Subject: [PATCH 11/16] avoid bad import --- clients/python/client/osparc/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/python/client/osparc/__init__.py b/clients/python/client/osparc/__init__.py index 59d57a8b..6077db98 100644 --- a/clients/python/client/osparc/__init__.py +++ b/clients/python/client/osparc/__init__.py @@ -9,6 +9,7 @@ ApiTypeError, ApiValueError, BodyUploadFileV0FilesContentPut, + Configuration, ErrorGet, File, Groups, @@ -37,7 +38,6 @@ from packaging.version import Version from ._api_client import ApiClient -from ._configuration import Configuration from ._exceptions import RequestError, VisibleDeprecationWarning from ._files_api import FilesApi from ._info import openapi From 14c52c669810f8e6818334345f60eded68222b9a Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 13:55:25 +0200 Subject: [PATCH 12/16] fix import --- clients/python/client/osparc/_http_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/python/client/osparc/_http_client.py b/clients/python/client/osparc/_http_client.py index 376cf19f..98b8c6a6 100644 --- a/clients/python/client/osparc/_http_client.py +++ b/clients/python/client/osparc/_http_client.py @@ -4,7 +4,7 @@ import httpx import tenacity -from ._configuration import Configuration +from osparc_client import Configuration _RETRY_AFTER_STATUS_CODES: Set[int] = {429, 503} From 5d782ee9c836d61e7f95df9d9e561707ce670e8a Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 14:08:12 +0200 Subject: [PATCH 13/16] fix e2e tests --- clients/python/client/osparc/_api_client.py | 4 ++- clients/python/test/e2e/conftest.py | 30 ++++++++------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/clients/python/client/osparc/_api_client.py b/clients/python/client/osparc/_api_client.py index e2d40f67..a30c51d5 100644 --- a/clients/python/client/osparc/_api_client.py +++ b/clients/python/client/osparc/_api_client.py @@ -20,7 +20,9 @@ def __init__( try: env_vars = ConfigurationModel() configuration = Configuration( - host=f"{env_vars.OSPARC_API_HOST}", + host=f"{env_vars.OSPARC_API_HOST}".rstrip( + "/" + ), # https://github.com/pydantic/pydantic/issues/7186 username=env_vars.OSPARC_API_KEY, password=env_vars.OSPARC_API_SECRET, ) diff --git a/clients/python/test/e2e/conftest.py b/clients/python/test/e2e/conftest.py index 270c6118..d8f4b1b9 100644 --- a/clients/python/test/e2e/conftest.py +++ b/clients/python/test/e2e/conftest.py @@ -8,6 +8,7 @@ import pytest from httpx import AsyncClient, BasicAuth from numpy import random +from osparc._models import ConfigurationModel from pydantic import ByteSize _KB: ByteSize = ByteSize(1024) # in bytes @@ -47,7 +48,6 @@ def pytest_runtest_makereport(item, call): Hook to add extra information when a test fails. """ if call.when == "call": - # Check if the test failed if call.excinfo is not None: test_name = item.name @@ -65,7 +65,9 @@ def pytest_runtest_makereport(item, call): end_time = _utc_now() if start_time: - diagnostics["graylog_url"] = _construct_graylog_url(api_host, start_time, end_time) + diagnostics["graylog_url"] = _construct_graylog_url( + api_host, start_time, end_time + ) # Print the diagnostics print(f"\nDiagnostics for {test_name}:") @@ -80,29 +82,19 @@ def pytest_configure(config): @pytest.fixture -def configuration() -> Iterable[osparc.Configuration]: - assert (host := os.environ.get("OSPARC_API_HOST")) - assert (username := os.environ.get("OSPARC_API_KEY")) - assert (password := os.environ.get("OSPARC_API_SECRET")) - yield osparc.Configuration( - host=host, - username=username, - password=password, - ) - - -@pytest.fixture -def api_client(configuration: osparc.Configuration) -> Iterable[osparc.ApiClient]: - with osparc.ApiClient(configuration=configuration) as api_client: +def api_client() -> Iterable[osparc.ApiClient]: + with osparc.ApiClient() as api_client: yield api_client @pytest.fixture -def async_client(configuration) -> Iterable[AsyncClient]: +def async_client() -> Iterable[AsyncClient]: + configuration = ConfigurationModel() yield AsyncClient( - base_url=configuration.host, + base_url=f"{configuration.OSPARC_API_HOST}".rstrip("/"), auth=BasicAuth( - username=configuration.username, password=configuration.password + username=configuration.OSPARC_API_KEY, + password=configuration.OSPARC_API_SECRET, ), ) # type: ignore From 7442aa463199dd65331089a3eadad369da53a12d Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 14:23:12 +0200 Subject: [PATCH 14/16] add unit test --- clients/python/test/test_osparc/test_apis.py | 58 ++++++++++---------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/clients/python/test/test_osparc/test_apis.py b/clients/python/test/test_osparc/test_apis.py index 04dbe166..869bbb5d 100644 --- a/clients/python/test/test_osparc/test_apis.py +++ b/clients/python/test/test_osparc/test_apis.py @@ -1,9 +1,9 @@ import os -from typing import Callable +from typing import Callable, Optional import pytest from faker import Faker -from osparc import ApiClient, Configuration, SolversApi, StudiesApi +from osparc import ApiClient, SolversApi, StudiesApi from pytest_mock import MockerFixture @@ -61,33 +61,35 @@ def check_headers(**kwargs): studies_api.clone_study(study_id=faker.uuid4()) -def test_configuration_constructor(monkeypatch: pytest.MonkeyPatch): +@pytest.mark.parametrize( + "OSPARC_API_HOST", ["https://api.foo.com", "https://api.bar.com/", None] +) +@pytest.mark.parametrize("OSPARC_API_KEY", ["key", None]) +@pytest.mark.parametrize("OSPARC_API_SECRET", ["secret", None]) +def test_api_client_constructor( + monkeypatch: pytest.MonkeyPatch, + OSPARC_API_HOST: Optional[str], + OSPARC_API_KEY: Optional[str], + OSPARC_API_SECRET: Optional[str], +): with monkeypatch.context() as patch: - patch.delenv("OSPARC_API_BASE_URL", raising=False) + patch.delenv("OSPARC_API_HOST", raising=False) patch.delenv("OSPARC_API_KEY", raising=False) patch.delenv("OSPARC_API_SECRET", raising=False) - config = Configuration() - assert config.host == "https://api.osparc.io" - assert config.username is None - assert config.password is None - - with monkeypatch.context() as patch: - patch.setenv("OSPARC_API_BASE_URL", "https://api.foo.com") - patch.setenv("OSPARC_API_KEY", "key") - patch.setenv("OSPARC_API_SECRET", "secret") - - config = Configuration() - assert config.host == "https://api.foo.com" - assert config.username == "key" - assert config.password == "secret" - - api = ApiClient() - assert api.configuration.host == config.host - assert api.configuration.username == config.username - assert api.configuration.password == config.password - - config = Configuration(username="foo") - assert config.host == "https://api.foo.com" - assert config.username == "foo" - assert config.password == "secret" + if OSPARC_API_HOST is not None: + patch.setenv("OSPARC_API_HOST", OSPARC_API_HOST) + if OSPARC_API_KEY is not None: + patch.setenv("OSPARC_API_KEY", OSPARC_API_KEY) + if OSPARC_API_SECRET is not None: + patch.setenv("OSPARC_API_SECRET", OSPARC_API_SECRET) + + if OSPARC_API_HOST and OSPARC_API_KEY and OSPARC_API_SECRET: + api = ApiClient() + assert api.configuration.host == OSPARC_API_HOST.rstrip("/") + assert api.configuration.username == OSPARC_API_KEY + assert api.configuration.password == OSPARC_API_SECRET + + else: + with pytest.raises(RuntimeError): + ApiClient() From 8cc4a75662c1e20d5aa62a44845fa853ddc051de Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 14:40:51 +0200 Subject: [PATCH 15/16] require api_client in wrapped apis --- clients/python/client/osparc/_files_api.py | 5 +++-- clients/python/client/osparc/_solvers_api.py | 4 ++-- clients/python/client/osparc/_studies_api.py | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/clients/python/client/osparc/_files_api.py b/clients/python/client/osparc/_files_api.py index 401e43b5..a9b8bd42 100644 --- a/clients/python/client/osparc/_files_api.py +++ b/clients/python/client/osparc/_files_api.py @@ -21,7 +21,8 @@ from tqdm.asyncio import tqdm from tqdm.contrib.logging import logging_redirect_tqdm -from . import ApiClient, File +from . import File +from ._api_client import ApiClient from ._http_client import AsyncHttpClient from ._utils import ( DEFAULT_TIMEOUT_SECONDS, @@ -36,7 +37,7 @@ class FilesApi(_FilesApi): """Class for interacting with files""" - def __init__(self, api_client: Optional[ApiClient] = None): + def __init__(self, api_client: ApiClient): """Construct object Args: diff --git a/clients/python/client/osparc/_solvers_api.py b/clients/python/client/osparc/_solvers_api.py index 714337a2..6a3d6aa2 100644 --- a/clients/python/client/osparc/_solvers_api.py +++ b/clients/python/client/osparc/_solvers_api.py @@ -4,7 +4,7 @@ from osparc_client import JobInputs, OnePageSolverPort, SolverPort from osparc_client import SolversApi as _SolversApi -from . import ApiClient +from ._api_client import ApiClient from ._models import ParentProjectInfo from ._utils import ( _DEFAULT_PAGINATION_LIMIT, @@ -27,7 +27,7 @@ def __getattr__(self, name: str) -> Any: raise NotImplementedError(f"SolversApi.{name} is still under development") return super().__getattribute__(name) - def __init__(self, api_client: Optional[ApiClient] = None): + def __init__(self, api_client: ApiClient): """Construct object Args: diff --git a/clients/python/client/osparc/_studies_api.py b/clients/python/client/osparc/_studies_api.py index 3bc07578..887b99df 100644 --- a/clients/python/client/osparc/_studies_api.py +++ b/clients/python/client/osparc/_studies_api.py @@ -5,10 +5,11 @@ from typing import Any, Optional import httpx -from osparc_client import ApiClient, JobInputs, JobLogsMap, PageStudy +from osparc_client import JobInputs, JobLogsMap, PageStudy from osparc_client import StudiesApi as _StudiesApi from tqdm.asyncio import tqdm_asyncio +from ._api_client import ApiClient from ._http_client import AsyncHttpClient from ._models import ParentProjectInfo from ._utils import ( @@ -39,7 +40,7 @@ class StudiesApi(_StudiesApi): "stop_study_job", ] - def __init__(self, api_client: Optional[ApiClient] = None): + def __init__(self, api_client: ApiClient): """Construct object Args: From eee80b1f50e039be2df51a925e03108c982a7dc9 Mon Sep 17 00:00:00 2001 From: Mads Bisgaard Date: Fri, 12 Jul 2024 14:56:51 +0200 Subject: [PATCH 16/16] fix unit tests --- clients/python/test/test_osparc/conftest.py | 5 +++++ clients/python/test/test_osparc/test_apis.py | 5 +++-- .../test/test_osparc/test_osparc_client/test_files_api.py | 6 ++++-- .../test/test_osparc/test_osparc_client/test_meta_api.py | 6 ++++-- .../test/test_osparc/test_osparc_client/test_solvers_api.py | 6 ++++-- .../test/test_osparc/test_osparc_client/test_users_api.py | 6 ++++-- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/clients/python/test/test_osparc/conftest.py b/clients/python/test/test_osparc/conftest.py index 70bcf701..67dfd069 100644 --- a/clients/python/test/test_osparc/conftest.py +++ b/clients/python/test/test_osparc/conftest.py @@ -12,6 +12,11 @@ def cfg(faker: Faker) -> osparc.Configuration: ) +@pytest.fixture +def api_client(cfg: osparc.Configuration) -> osparc.ApiClient: + return osparc.ApiClient(configuration=cfg) + + @pytest.fixture def dev_mode_enabled(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setenv("OSPARC_DEV_FEATURES_ENABLED", "1") diff --git a/clients/python/test/test_osparc/test_apis.py b/clients/python/test/test_osparc/test_apis.py index 89d3063f..4f01a961 100644 --- a/clients/python/test/test_osparc/test_apis.py +++ b/clients/python/test/test_osparc/test_apis.py @@ -31,6 +31,7 @@ def test_create_jobs_parent_headers( create_parent_env: Callable, dev_mode_enabled: None, parent_env: bool, + api_client: ApiClient, ): create_parent_env(parent_env) @@ -58,10 +59,10 @@ def check_headers(**kwargs): side_effect=lambda study_id, **kwargs: check_headers(**kwargs), ) - solvers_api = SolversApi() + solvers_api = SolversApi(api_client=api_client) solvers_api.create_job(solver_key="mysolver", version="1.2.3", job_inputs={}) - studies_api = StudiesApi() + studies_api = StudiesApi(api_client=api_client) studies_api.create_study_job(study_id=faker.uuid4(), job_inputs={}) studies_api.clone_study(study_id=faker.uuid4()) diff --git a/clients/python/test/test_osparc/test_osparc_client/test_files_api.py b/clients/python/test/test_osparc/test_osparc_client/test_files_api.py index 62bfa9a4..d08ccad7 100644 --- a/clients/python/test/test_osparc/test_osparc_client/test_files_api.py +++ b/clients/python/test/test_osparc/test_osparc_client/test_files_api.py @@ -14,14 +14,16 @@ import unittest -from osparc import FilesApi # noqa: E501 +from osparc import ApiClient, Configuration, FilesApi # noqa: E501 class TestFilesApi(unittest.TestCase): """FilesApi unit test stubs""" def setUp(self): - self.api = FilesApi() # noqa: E501 + self.api = FilesApi( + api_client=ApiClient(configuration=Configuration()) + ) # noqa: E501 def tearDown(self): pass diff --git a/clients/python/test/test_osparc/test_osparc_client/test_meta_api.py b/clients/python/test/test_osparc/test_osparc_client/test_meta_api.py index 44dbdd23..3499ff77 100644 --- a/clients/python/test/test_osparc/test_osparc_client/test_meta_api.py +++ b/clients/python/test/test_osparc/test_osparc_client/test_meta_api.py @@ -14,14 +14,16 @@ import unittest -from osparc import MetaApi # noqa: E501 +from osparc import ApiClient, Configuration, MetaApi # noqa: E501 class TestMetaApi(unittest.TestCase): """MetaApi unit test stubs""" def setUp(self): - self.api = MetaApi() # noqa: E501 + self.api = MetaApi( + api_client=ApiClient(configuration=Configuration()) + ) # noqa: E501 def tearDown(self): pass diff --git a/clients/python/test/test_osparc/test_osparc_client/test_solvers_api.py b/clients/python/test/test_osparc/test_osparc_client/test_solvers_api.py index 55709aaa..71078984 100644 --- a/clients/python/test/test_osparc/test_osparc_client/test_solvers_api.py +++ b/clients/python/test/test_osparc/test_osparc_client/test_solvers_api.py @@ -14,14 +14,16 @@ import unittest -from osparc import SolversApi # noqa: E501 +from osparc import ApiClient, Configuration, SolversApi # noqa: E501 class TestSolversApi(unittest.TestCase): """SolversApi unit test stubs""" def setUp(self): - self.api = SolversApi() # noqa: E501 + self.api = SolversApi( + api_client=ApiClient(configuration=Configuration()) + ) # noqa: E501 def tearDown(self): pass diff --git a/clients/python/test/test_osparc/test_osparc_client/test_users_api.py b/clients/python/test/test_osparc/test_osparc_client/test_users_api.py index f4a3cf7a..ae4073c6 100644 --- a/clients/python/test/test_osparc/test_osparc_client/test_users_api.py +++ b/clients/python/test/test_osparc/test_osparc_client/test_users_api.py @@ -14,14 +14,16 @@ import unittest -from osparc import UsersApi # noqa: E501 +from osparc import ApiClient, Configuration, UsersApi # noqa: E501 class TestUsersApi(unittest.TestCase): """UsersApi unit test stubs""" def setUp(self): - self.api = UsersApi() # noqa: E501 + self.api = UsersApi( + api_client=ApiClient(configuration=Configuration()) + ) # noqa: E501 def tearDown(self): pass