diff --git a/packages/common-library/src/common_library/pydantic_networks_extension.py b/packages/common-library/src/common_library/pydantic_networks_extension.py deleted file mode 100644 index 1e85a741760..00000000000 --- a/packages/common-library/src/common_library/pydantic_networks_extension.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Annotated, TypeAlias - -from pydantic import AfterValidator, AnyHttpUrl, HttpUrl -from pydantic_core import Url - - -def _strip_last_slash(url: Url) -> str: - return f"{url}".rstrip("/") - - -AnyHttpUrlLegacy: TypeAlias = Annotated[ - AnyHttpUrl, - AfterValidator(_strip_last_slash), -] - - -HttpUrlLegacy: TypeAlias = Annotated[ - HttpUrl, - AfterValidator(_strip_last_slash), -] diff --git a/packages/common-library/tests/test_pydantic_networks_extension.py b/packages/common-library/tests/test_pydantic_networks_extension.py deleted file mode 100644 index 6ab50a42a2b..00000000000 --- a/packages/common-library/tests/test_pydantic_networks_extension.py +++ /dev/null @@ -1,39 +0,0 @@ -import pytest -from common_library.pydantic_networks_extension import AnyHttpUrlLegacy -from pydantic import AnyHttpUrl, BaseModel, TypeAdapter, ValidationError -from pydantic_core import Url - - -class A(BaseModel): - url: AnyHttpUrlLegacy - - -def test_any_http_url(): - url = TypeAdapter(AnyHttpUrl).validate_python( - "http://backgroud.testserver.io", - ) - - assert isinstance(url, Url) - assert ( - f"{url}" == "http://backgroud.testserver.io/" - ) # trailing slash added (in Pydantic v2) - - -def test_any_http_url_legacy(): - url = TypeAdapter(AnyHttpUrlLegacy).validate_python( - "http://backgroud.testserver.io", - ) - - assert isinstance(url, str) - assert url == "http://backgroud.testserver.io" # no trailing slash was added - - -def test_valid_any_http_url_legacy_field(): - a = A(url="http://backgroud.testserver.io") # type: ignore - - assert a.url == "http://backgroud.testserver.io" # no trailing slash was added - - -def test_not_valid_any_http_url_legacy_field(): - with pytest.raises(ValidationError): - A(url="htttttp://backgroud.testserver.io") # type: ignore diff --git a/packages/models-library/src/models_library/rest_pagination.py b/packages/models-library/src/models_library/rest_pagination.py index cd6420ca174..b2c82726798 100644 --- a/packages/models-library/src/models_library/rest_pagination.py +++ b/packages/models-library/src/models_library/rest_pagination.py @@ -1,7 +1,7 @@ from typing import Annotated, Final, Generic, TypeAlias, TypeVar -from common_library.pydantic_networks_extension import AnyHttpUrlLegacy from pydantic import ( + AnyHttpUrl, BaseModel, BeforeValidator, ConfigDict, @@ -100,9 +100,7 @@ class PageLinks( PageRefs[ Annotated[ str, - BeforeValidator( - lambda x: str(TypeAdapter(AnyHttpUrlLegacy).validate_python(x)) - ), + BeforeValidator(lambda x: str(TypeAdapter(AnyHttpUrl).validate_python(x))), ] ] ): diff --git a/packages/models-library/src/models_library/rest_pagination_utils.py b/packages/models-library/src/models_library/rest_pagination_utils.py index 6399fe652a3..65c89131fe5 100644 --- a/packages/models-library/src/models_library/rest_pagination_utils.py +++ b/packages/models-library/src/models_library/rest_pagination_utils.py @@ -1,7 +1,7 @@ from math import ceil from typing import Any, Protocol, runtime_checkable -from common_library.pydantic_networks_extension import AnyHttpUrlLegacy +from pydantic import AnyHttpUrl, TypeAdapter from pydantic import TypeAdapter from typing_extensions import ( # https://docs.pydantic.dev/latest/api/standard_library_types/#typeddict TypedDict, @@ -44,7 +44,7 @@ def _replace_query(url: _URLType, query: dict[str, Any]) -> str: new_url = url.replace_query_params(**query) new_url_str = f"{new_url}" - return f"{TypeAdapter(AnyHttpUrlLegacy).validate_python(new_url_str)}" + return f"{TypeAdapter(AnyHttpUrl).validate_python(new_url_str)}" class PageDict(TypedDict): diff --git a/packages/settings-library/src/settings_library/ssm.py b/packages/settings-library/src/settings_library/ssm.py index 823ac57c1a2..8bed0906bbe 100644 --- a/packages/settings-library/src/settings_library/ssm.py +++ b/packages/settings-library/src/settings_library/ssm.py @@ -1,7 +1,6 @@ from typing import Annotated -from common_library.pydantic_networks_extension import AnyHttpUrlLegacy -from pydantic import BeforeValidator, Field, SecretStr, TypeAdapter +from pydantic import AnyHttpUrl, BeforeValidator, Field, SecretStr, TypeAdapter from pydantic_settings import SettingsConfigDict from .base import BaseCustomSettings @@ -12,9 +11,7 @@ class SSMSettings(BaseCustomSettings): SSM_ENDPOINT: ( Annotated[ str, - BeforeValidator( - lambda x: str(TypeAdapter(AnyHttpUrlLegacy).validate_python(x)) - ), + BeforeValidator(lambda x: str(TypeAdapter(AnyHttpUrl).validate_python(x))), ] | None ) = Field(default=None, description="do not define if using standard AWS") diff --git a/services/agent/src/simcore_service_agent/core/settings.py b/services/agent/src/simcore_service_agent/core/settings.py index 3f7af297189..40370257c4a 100644 --- a/services/agent/src/simcore_service_agent/core/settings.py +++ b/services/agent/src/simcore_service_agent/core/settings.py @@ -1,8 +1,7 @@ from datetime import timedelta -from common_library.pydantic_networks_extension import AnyHttpUrlLegacy from models_library.basic_types import BootModeEnum, LogLevel -from pydantic import AliasChoices, Field, field_validator +from pydantic import AliasChoices, AnyHttpUrl, Field, field_validator from servicelib.logging_utils_filtering import LoggerName, MessageSubstring from settings_library.base import BaseCustomSettings from settings_library.r_clone import S3Provider @@ -43,7 +42,7 @@ class ApplicationSettings(BaseCustomSettings, MixinLoggingSettings): AGENT_VOLUMES_CLEANUP_TARGET_SWARM_STACK_NAME: str = Field( ..., description="Exactly the same as director-v2's `SWARM_STACK_NAME` env var" ) - AGENT_VOLUMES_CLEANUP_S3_ENDPOINT: AnyHttpUrlLegacy + AGENT_VOLUMES_CLEANUP_S3_ENDPOINT: AnyHttpUrl AGENT_VOLUMES_CLEANUP_S3_ACCESS_KEY: str AGENT_VOLUMES_CLEANUP_S3_SECRET_KEY: str AGENT_VOLUMES_CLEANUP_S3_BUCKET: str diff --git a/services/agent/tests/conftest.py b/services/agent/tests/conftest.py index a0c59ca9f37..f421258fd77 100644 --- a/services/agent/tests/conftest.py +++ b/services/agent/tests/conftest.py @@ -3,7 +3,6 @@ import pytest -from common_library.pydantic_networks_extension import HttpUrlLegacy from faker import Faker from models_library.basic_types import BootModeEnum from moto.server import ThreadedMotoServer @@ -65,8 +64,8 @@ def mock_environment( @pytest.fixture(scope="module") -def mocked_s3_server_url(mocked_aws_server: ThreadedMotoServer) -> HttpUrlLegacy: +def mocked_s3_server_url(mocked_aws_server: ThreadedMotoServer) -> HttpUrl: # pylint: disable=protected-access - return TypeAdapter(HttpUrlLegacy).validate_python( + return TypeAdapter(HttpUrl).validate_python( f"http://{mocked_aws_server._ip_address}:{mocked_aws_server._port}", # noqa: SLF001 ) diff --git a/services/invitations/src/simcore_service_invitations/api/_meta.py b/services/invitations/src/simcore_service_invitations/api/_meta.py index 49d3f4b48cf..621f3b4445e 100644 --- a/services/invitations/src/simcore_service_invitations/api/_meta.py +++ b/services/invitations/src/simcore_service_invitations/api/_meta.py @@ -2,8 +2,7 @@ from collections.abc import Callable from fastapi import APIRouter, Depends -from pydantic import BaseModel -from common_library.pydantic_networks_extension import HttpUrlLegacy +from pydantic import BaseModel, HttpUrl from .._meta import API_VERSION, PROJECT_NAME from ._dependencies import get_reverse_url_mapper @@ -21,7 +20,7 @@ class _Meta(BaseModel): name: str version: str - docs_url: HttpUrlLegacy + docs_url: HttpUrl # diff --git a/services/invitations/src/simcore_service_invitations/services/invitations.py b/services/invitations/src/simcore_service_invitations/services/invitations.py index 1cdc33f4085..e9d0a2a13ed 100644 --- a/services/invitations/src/simcore_service_invitations/services/invitations.py +++ b/services/invitations/src/simcore_service_invitations/services/invitations.py @@ -3,7 +3,6 @@ import logging from urllib import parse -from common_library.pydantic_networks_extension import HttpUrlLegacy from cryptography.fernet import Fernet, InvalidToken from models_library.invitations import InvitationContent, InvitationInputs from models_library.products import ProductName @@ -67,7 +66,7 @@ def _build_link( # Adds query to fragment base_url = f"{base_url}/" url = URL(base_url).replace(fragment=f"{r}") - return TypeAdapter(HttpUrlLegacy).validate_python(f"{url}") + return TypeAdapter(HttpUrl).validate_python(f"{url}") def _fernet_encrypt_as_urlsafe_code( diff --git a/services/invitations/tests/unit/api/test_api_invitations.py b/services/invitations/tests/unit/api/test_api_invitations.py index 95d5eeeece0..751a0a96bb9 100644 --- a/services/invitations/tests/unit/api/test_api_invitations.py +++ b/services/invitations/tests/unit/api/test_api_invitations.py @@ -100,7 +100,7 @@ def test_check_valid_invitation( # check invitation_url response = client.post( f"/{API_VTAG}/invitations:extract", - json={"invitation_url": invitation_url}, + json={"invitation_url": f"{invitation_url}"}, auth=basic_auth, ) assert response.status_code == 200, f"{response.json()=}" @@ -130,7 +130,7 @@ def test_check_invalid_invitation_with_different_secret( # check invitation_url response = client.post( f"/{API_VTAG}/invitations:extract", - json={"invitation_url": invitation_url}, + json={"invitation_url": f"{invitation_url}"}, auth=basic_auth, ) assert ( @@ -173,7 +173,7 @@ def test_check_invalid_invitation_with_wrong_code( default_product=default_product, ) - invitation_url_with_invalid_code = invitation_url[:-3] + invitation_url_with_invalid_code = f"{invitation_url}"[:-3] # check invitation_url response = client.post( diff --git a/services/invitations/tests/unit/test_invitations.py b/services/invitations/tests/unit/test_invitations.py index 0e6ea34b18c..b37b79f4575 100644 --- a/services/invitations/tests/unit/test_invitations.py +++ b/services/invitations/tests/unit/test_invitations.py @@ -73,8 +73,8 @@ def test_create_and_decrypt_invitation( base_url=faker.url(), default_product=default_product, ) - assert URL(invitation_link).fragment - query_params = dict(parse.parse_qsl((URL(URL(invitation_link).fragment).query))) + assert URL(f"{invitation_link}").fragment + query_params = dict(parse.parse_qsl(URL(URL(f"{invitation_link}").fragment).query)) # will raise TokenError or ValidationError invitation = decrypt_invitation( @@ -196,4 +196,10 @@ class OtherModel(BaseModel): def test_aliases_uniqueness(): - assert not [item for item, count in Counter([field.alias for field in _ContentWithShortNames.model_fields.values()]).items() if count > 1] #nosec + assert not [ + item + for item, count in Counter( + [field.alias for field in _ContentWithShortNames.model_fields.values()] + ).items() + if count > 1 + ] # nosec diff --git a/services/payments/src/simcore_service_payments/core/settings.py b/services/payments/src/simcore_service_payments/core/settings.py index a5075e8e4ca..41f1bb7e9b3 100644 --- a/services/payments/src/simcore_service_payments/core/settings.py +++ b/services/payments/src/simcore_service_payments/core/settings.py @@ -1,11 +1,11 @@ from functools import cached_property -from common_library.pydantic_networks_extension import HttpUrlLegacy from models_library.basic_types import NonNegativeDecimal from pydantic import ( AliasChoices, EmailStr, Field, + HttpUrl, PositiveFloat, SecretStr, TypeAdapter, @@ -69,7 +69,7 @@ class ApplicationSettings(_BaseApplicationSettings): These settings includes extra configuration for the http-API """ - PAYMENTS_GATEWAY_URL: HttpUrlLegacy = Field( + PAYMENTS_GATEWAY_URL: HttpUrl = Field( ..., description="Base url to the payment gateway" ) @@ -134,7 +134,7 @@ class ApplicationSettings(_BaseApplicationSettings): description="settings for postgres service", ) - PAYMENTS_STRIPE_URL: HttpUrlLegacy = Field( + PAYMENTS_STRIPE_URL: HttpUrl = Field( ..., description="Base url to the payment Stripe" ) PAYMENTS_STRIPE_API_SECRET: SecretStr = Field( diff --git a/services/payments/src/simcore_service_payments/services/payments_gateway.py b/services/payments/src/simcore_service_payments/services/payments_gateway.py index 34af4fa2268..812ab087074 100644 --- a/services/payments/src/simcore_service_payments/services/payments_gateway.py +++ b/services/payments/src/simcore_service_payments/services/payments_gateway.py @@ -209,7 +209,7 @@ def setup_payments_gateway(app: FastAPI): # create api = PaymentsGatewayApi.from_client_kwargs( - base_url=settings.PAYMENTS_GATEWAY_URL, + base_url=f"{settings.PAYMENTS_GATEWAY_URL}", headers={"accept": "application/json"}, auth=_GatewayApiAuth( secret=settings.PAYMENTS_GATEWAY_API_SECRET.get_secret_value() diff --git a/services/payments/src/simcore_service_payments/services/stripe.py b/services/payments/src/simcore_service_payments/services/stripe.py index 9a701965beb..349de908d7e 100644 --- a/services/payments/src/simcore_service_payments/services/stripe.py +++ b/services/payments/src/simcore_service_payments/services/stripe.py @@ -89,7 +89,7 @@ def setup_stripe(app: FastAPI): assert app.state # nosec settings: ApplicationSettings = app.state.settings api = StripeApi.from_client_kwargs( - base_url=settings.PAYMENTS_STRIPE_URL, + base_url=f"{settings.PAYMENTS_STRIPE_URL}", auth=_StripeBearerAuth(settings.PAYMENTS_STRIPE_API_SECRET.get_secret_value()), ) if settings.PAYMENTS_TRACING: diff --git a/services/payments/tests/unit/conftest.py b/services/payments/tests/unit/conftest.py index be55736c6f6..de408dadf3d 100644 --- a/services/payments/tests/unit/conftest.py +++ b/services/payments/tests/unit/conftest.py @@ -198,7 +198,7 @@ def mock_payments_gateway_service_api_base(app: FastAPI) -> Iterator[MockRouter] settings: ApplicationSettings = app.state.settings with respx.mock( - base_url=settings.PAYMENTS_GATEWAY_URL, + base_url=f"{settings.PAYMENTS_GATEWAY_URL}", assert_all_called=False, assert_all_mocked=True, # IMPORTANT: KEEP always True! ) as respx_mock: @@ -410,7 +410,7 @@ def mock_payments_stripe_api_base(app: FastAPI) -> Iterator[MockRouter]: settings: ApplicationSettings = app.state.settings with respx.mock( - base_url=settings.PAYMENTS_STRIPE_URL, + base_url=f"{settings.PAYMENTS_STRIPE_URL}", assert_all_called=False, assert_all_mocked=True, # IMPORTANT: KEEP always True! ) as respx_mock: diff --git a/services/payments/tests/unit/test_services_payments_gateway.py b/services/payments/tests/unit/test_services_payments_gateway.py index e89c502894b..c2ba73f4f9a 100644 --- a/services/payments/tests/unit/test_services_payments_gateway.py +++ b/services/payments/tests/unit/test_services_payments_gateway.py @@ -121,7 +121,7 @@ async def test_one_time_payment_workflow( ) app_settings: ApplicationSettings = app.state.settings - assert submission_link.host == URL(app_settings.PAYMENTS_GATEWAY_URL).host + assert submission_link.host == URL(f"{app_settings.PAYMENTS_GATEWAY_URL}").host # cancel payment_canceled = await payment_gateway_api.cancel_payment(payment_initiated) @@ -160,7 +160,7 @@ async def test_payment_methods_workflow( ) app_settings: ApplicationSettings = app.state.settings - assert form_link.host == URL(app_settings.PAYMENTS_GATEWAY_URL).host + assert form_link.host == URL(f"{app_settings.PAYMENTS_GATEWAY_URL}").host # CRUD payment_method_id = initiated.payment_method_id