diff --git a/diracx-cli/pyproject.toml b/diracx-cli/pyproject.toml index d33abfb6..06d52667 100644 --- a/diracx-cli/pyproject.toml +++ b/diracx-cli/pyproject.toml @@ -18,7 +18,7 @@ dependencies = [ "diracx-client", "diracx-core", "gitpython", - "pydantic", + "pydantic>=2.10", "rich", "typer", "pyyaml", diff --git a/diracx-client/src/diracx/client/generated/__init__.py b/diracx-client/src/diracx/client/generated/__init__.py index b01cfdc2..6747652b 100644 --- a/diracx-client/src/diracx/client/generated/__init__.py +++ b/diracx-client/src/diracx/client/generated/__init__.py @@ -1,14 +1,20 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._client import Dirac +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._client import Dirac # type: ignore try: from ._patch import __all__ as _patch_all - from ._patch import * # pylint: disable=unused-wildcard-import + from ._patch import * except ImportError: _patch_all = [] from ._patch import patch_sdk as _patch_sdk diff --git a/diracx-client/src/diracx/client/generated/_client.py b/diracx-client/src/diracx/client/generated/_client.py index 231f5ef4..310dea0d 100644 --- a/diracx-client/src/diracx/client/generated/_client.py +++ b/diracx-client/src/diracx/client/generated/_client.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/diracx-client/src/diracx/client/generated/_configuration.py b/diracx-client/src/diracx/client/generated/_configuration.py index 53346cd8..0d22b46e 100644 --- a/diracx-client/src/diracx/client/generated/_configuration.py +++ b/diracx-client/src/diracx/client/generated/_configuration.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/diracx-client/src/diracx/client/generated/_serialization.py b/diracx-client/src/diracx/client/generated/_serialization.py index a058c396..a31505cf 100644 --- a/diracx-client/src/diracx/client/generated/_serialization.py +++ b/diracx-client/src/diracx/client/generated/_serialization.py @@ -1,3 +1,4 @@ +# pylint: disable=too-many-lines # -------------------------------------------------------------------------- # # Copyright (c) Microsoft Corporation. All rights reserved. @@ -536,7 +537,6 @@ def _flatten_subtype(cls, key, objects): def _classify(cls, response, objects): """Check the class _subtype_map for any child classes. We want to ignore any inherited _subtype_maps. - Remove the polymorphic key from the initial data. :param dict response: The initial data :param dict objects: The class objects @@ -548,9 +548,9 @@ def _classify(cls, response, objects): if not isinstance(response, ET.Element): rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] - subtype_value = response.pop( + subtype_value = response.get( rest_api_response_key, None - ) or response.pop(subtype_key, None) + ) or response.get(subtype_key, None) else: subtype_value = xml_key_extractor( subtype_key, cls._attribute_map[subtype_key], response @@ -1802,13 +1802,13 @@ def _instantiate_model(self, response, attrs, additional_properties=None): try: readonly = [ k - for k, v in response._validation.items() - if v.get("readonly") # pylint: disable=protected-access + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") ] const = [ k - for k, v in response._validation.items() - if v.get("constant") # pylint: disable=protected-access + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") ] kwargs = { k: v @@ -1819,7 +1819,7 @@ def _instantiate_model(self, response, attrs, additional_properties=None): for attr in readonly: setattr(response_obj, attr, attrs.get(attr)) if additional_properties: - response_obj.additional_properties = additional_properties + response_obj.additional_properties = additional_properties # type: ignore return response_obj except TypeError as err: msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore diff --git a/diracx-client/src/diracx/client/generated/_vendor.py b/diracx-client/src/diracx/client/generated/_vendor.py index 68bb7b81..21c789fa 100644 --- a/diracx-client/src/diracx/client/generated/_vendor.py +++ b/diracx-client/src/diracx/client/generated/_vendor.py @@ -1,5 +1,5 @@ # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/diracx-client/src/diracx/client/generated/aio/__init__.py b/diracx-client/src/diracx/client/generated/aio/__init__.py index b01cfdc2..6747652b 100644 --- a/diracx-client/src/diracx/client/generated/aio/__init__.py +++ b/diracx-client/src/diracx/client/generated/aio/__init__.py @@ -1,14 +1,20 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._client import Dirac +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._client import Dirac # type: ignore try: from ._patch import __all__ as _patch_all - from ._patch import * # pylint: disable=unused-wildcard-import + from ._patch import * except ImportError: _patch_all = [] from ._patch import patch_sdk as _patch_sdk diff --git a/diracx-client/src/diracx/client/generated/aio/_client.py b/diracx-client/src/diracx/client/generated/aio/_client.py index 4bdb75f2..a5052eb9 100644 --- a/diracx-client/src/diracx/client/generated/aio/_client.py +++ b/diracx-client/src/diracx/client/generated/aio/_client.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/diracx-client/src/diracx/client/generated/aio/_configuration.py b/diracx-client/src/diracx/client/generated/aio/_configuration.py index 086ea1c6..21546bc0 100644 --- a/diracx-client/src/diracx/client/generated/aio/_configuration.py +++ b/diracx-client/src/diracx/client/generated/aio/_configuration.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/diracx-client/src/diracx/client/generated/aio/_vendor.py b/diracx-client/src/diracx/client/generated/aio/_vendor.py index 68bb7b81..21c789fa 100644 --- a/diracx-client/src/diracx/client/generated/aio/_vendor.py +++ b/diracx-client/src/diracx/client/generated/aio/_vendor.py @@ -1,5 +1,5 @@ # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/diracx-client/src/diracx/client/generated/aio/operations/__init__.py b/diracx-client/src/diracx/client/generated/aio/operations/__init__.py index 96c3a8b8..b4db9d4e 100644 --- a/diracx-client/src/diracx/client/generated/aio/operations/__init__.py +++ b/diracx-client/src/diracx/client/generated/aio/operations/__init__.py @@ -1,16 +1,22 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._operations import WellKnownOperations -from ._operations import AuthOperations -from ._operations import ConfigOperations -from ._operations import JobsOperations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._operations import WellKnownOperations # type: ignore +from ._operations import AuthOperations # type: ignore +from ._operations import ConfigOperations # type: ignore +from ._operations import JobsOperations # type: ignore from ._patch import __all__ as _patch_all -from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ diff --git a/diracx-client/src/diracx/client/generated/aio/operations/_operations.py b/diracx-client/src/diracx/client/generated/aio/operations/_operations.py index a7568277..72211529 100644 --- a/diracx-client/src/diracx/client/generated/aio/operations/_operations.py +++ b/diracx-client/src/diracx/client/generated/aio/operations/_operations.py @@ -1,7 +1,7 @@ # pylint: disable=too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from io import IOBase @@ -236,9 +236,25 @@ async def initiate_device_flow( """Initiate Device Flow. Initiate the device flow against DIRAC authorization Server. - Scope must have exactly up to one ``group`` (otherwise default) and - one or more ``property`` scope. - If no property, then get default one. + + Scope details: + + + * + If only VO is provided: Uses the default group and its properties for the VO. + + * + If VO and group are provided: Uses the specified group and its properties for the VO. + + * + If VO and properties are provided: Uses the default group and combines its properties with + the + provided properties. + + * + If VO, group, and properties are provided: Uses the specified group and combines its + properties with the + provided properties. Offers the user to go with the browser to ``auth//device?user_code=XYZ``. @@ -633,9 +649,9 @@ async def userinfo(self, **kwargs: Any) -> _models.UserInfoResponse: async def authorization_flow( self, *, - response_type: Union[str, _models.Enum0], + response_type: str, code_challenge: str, - code_challenge_method: Union[str, _models.Enum1], + code_challenge_method: str, client_id: str, redirect_uri: str, scope: str, @@ -648,16 +664,35 @@ async def authorization_flow( It will redirect to the actual OpenID server (IAM, CheckIn) to perform a authorization code flow. + Scope details: + + + * + If only VO is provided: Uses the default group and its properties for the VO. + + * + If VO and group are provided: Uses the specified group and its properties for the VO. + + * + If VO and properties are provided: Uses the default group and combines its properties with + the + provided properties. + + * + If VO, group, and properties are provided: Uses the specified group and combines its + properties with the + provided properties. + We set the user details obtained from the user authorize flow in a cookie to be able to map the authorization flow with the corresponding user authorize flow. - :keyword response_type: "code" Required. - :paramtype response_type: str or ~generated.models.Enum0 + :keyword response_type: Required. + :paramtype response_type: str :keyword code_challenge: Required. :paramtype code_challenge: str - :keyword code_challenge_method: "S256" Required. - :paramtype code_challenge_method: str or ~generated.models.Enum1 + :keyword code_challenge_method: Required. + :paramtype code_challenge_method: str :keyword client_id: Required. :paramtype client_id: str :keyword redirect_uri: Required. diff --git a/diracx-client/src/diracx/client/generated/models/__init__.py b/diracx-client/src/diracx/client/generated/models/__init__.py index 42b444c1..13051e56 100644 --- a/diracx-client/src/diracx/client/generated/models/__init__.py +++ b/diracx-client/src/diracx/client/generated/models/__init__.py @@ -1,54 +1,60 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._models import BodyAuthToken -from ._models import BodyAuthTokenGrantType -from ._models import DevelopmentSettings -from ._models import GroupInfo -from ._models import HTTPValidationError -from ._models import InitiateDeviceFlowResponse -from ._models import InsertedJob -from ._models import JobSearchParams -from ._models import JobSearchParamsSearchItem -from ._models import JobStatusReturn -from ._models import JobStatusUpdate -from ._models import JobSummaryParams -from ._models import JobSummaryParamsSearchItem -from ._models import LimitedJobStatusReturn -from ._models import Metadata -from ._models import SandboxDownloadResponse -from ._models import SandboxInfo -from ._models import SandboxUploadResponse -from ._models import ScalarSearchSpec -from ._models import ScalarSearchSpecValue -from ._models import SetJobStatusReturn -from ._models import SortSpec -from ._models import SupportInfo -from ._models import TokenResponse -from ._models import UserInfoResponse -from ._models import VOInfo -from ._models import ValidationError -from ._models import ValidationErrorLocItem -from ._models import VectorSearchSpec -from ._models import VectorSearchSpecValues +from typing import TYPE_CHECKING -from ._enums import ChecksumAlgorithm -from ._enums import Enum0 -from ._enums import Enum1 -from ._enums import Enum2 -from ._enums import Enum3 -from ._enums import Enum4 -from ._enums import JobStatus -from ._enums import SandboxFormat -from ._enums import SandboxType -from ._enums import ScalarSearchOperator -from ._enums import SortDirection -from ._enums import VectorSearchOperator +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + + +from ._models import ( # type: ignore + BodyAuthToken, + BodyAuthTokenGrantType, + DevelopmentSettings, + GroupInfo, + HTTPValidationError, + InitiateDeviceFlowResponse, + InsertedJob, + JobSearchParams, + JobSearchParamsSearchItem, + JobStatusReturn, + JobStatusUpdate, + JobSummaryParams, + JobSummaryParamsSearchItem, + LimitedJobStatusReturn, + Metadata, + SandboxDownloadResponse, + SandboxInfo, + SandboxUploadResponse, + ScalarSearchSpec, + ScalarSearchSpecValue, + SetJobStatusReturn, + SortSpec, + SupportInfo, + TokenResponse, + UserInfoResponse, + VOInfo, + ValidationError, + ValidationErrorLocItem, + VectorSearchSpec, + VectorSearchSpecValues, +) + +from ._enums import ( # type: ignore + ChecksumAlgorithm, + JobStatus, + SandboxFormat, + SandboxType, + ScalarSearchOperator, + SortDirection, + VectorSearchOperator, +) from ._patch import __all__ as _patch_all -from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ @@ -83,11 +89,6 @@ "VectorSearchSpec", "VectorSearchSpecValues", "ChecksumAlgorithm", - "Enum0", - "Enum1", - "Enum2", - "Enum3", - "Enum4", "JobStatus", "SandboxFormat", "SandboxType", diff --git a/diracx-client/src/diracx/client/generated/models/_enums.py b/diracx-client/src/diracx/client/generated/models/_enums.py index d74055c9..a4aee653 100644 --- a/diracx-client/src/diracx/client/generated/models/_enums.py +++ b/diracx-client/src/diracx/client/generated/models/_enums.py @@ -1,6 +1,6 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- @@ -14,38 +14,6 @@ class ChecksumAlgorithm(str, Enum, metaclass=CaseInsensitiveEnumMeta): SHA256 = "sha256" -class Enum0(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Response Type.""" - - CODE = "code" - - -class Enum1(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Code Challenge Method.""" - - S256 = "S256" - - -class Enum2(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Enum2.""" - - AUTHORIZATION_CODE = "authorization_code" - - -class Enum3(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Enum3.""" - - URN_IETF_PARAMS_OAUTH_GRANT_TYPE_DEVICE_CODE = ( - "urn:ietf:params:oauth:grant-type:device_code" - ) - - -class Enum4(str, Enum, metaclass=CaseInsensitiveEnumMeta): - """Enum4.""" - - REFRESH_TOKEN = "refresh_token" - - class JobStatus(str, Enum, metaclass=CaseInsensitiveEnumMeta): """JobStatus.""" diff --git a/diracx-client/src/diracx/client/generated/models/_models.py b/diracx-client/src/diracx/client/generated/models/_models.py index 47b82e84..2d1fe3e4 100644 --- a/diracx-client/src/diracx/client/generated/models/_models.py +++ b/diracx-client/src/diracx/client/generated/models/_models.py @@ -1,7 +1,7 @@ # pylint: disable=too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- diff --git a/diracx-client/src/diracx/client/generated/operations/__init__.py b/diracx-client/src/diracx/client/generated/operations/__init__.py index 96c3a8b8..b4db9d4e 100644 --- a/diracx-client/src/diracx/client/generated/operations/__init__.py +++ b/diracx-client/src/diracx/client/generated/operations/__init__.py @@ -1,16 +1,22 @@ # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position -from ._operations import WellKnownOperations -from ._operations import AuthOperations -from ._operations import ConfigOperations -from ._operations import JobsOperations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._operations import WellKnownOperations # type: ignore +from ._operations import AuthOperations # type: ignore +from ._operations import ConfigOperations # type: ignore +from ._operations import JobsOperations # type: ignore from ._patch import __all__ as _patch_all -from ._patch import * # pylint: disable=unused-wildcard-import +from ._patch import * from ._patch import patch_sdk as _patch_sdk __all__ = [ diff --git a/diracx-client/src/diracx/client/generated/operations/_operations.py b/diracx-client/src/diracx/client/generated/operations/_operations.py index ca441334..98eb97f4 100644 --- a/diracx-client/src/diracx/client/generated/operations/_operations.py +++ b/diracx-client/src/diracx/client/generated/operations/_operations.py @@ -1,7 +1,7 @@ # pylint: disable=too-many-lines # coding=utf-8 # -------------------------------------------------------------------------- -# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/python@6.26.0) +# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.3, generator: @autorest/python@6.26.5) # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- from io import IOBase @@ -202,9 +202,9 @@ def build_auth_userinfo_request(**kwargs: Any) -> HttpRequest: def build_auth_authorization_flow_request( *, - response_type: Union[str, _models.Enum0], + response_type: str, code_challenge: str, - code_challenge_method: Union[str, _models.Enum1], + code_challenge_method: str, client_id: str, redirect_uri: str, scope: str, @@ -1060,9 +1060,25 @@ def initiate_device_flow( """Initiate Device Flow. Initiate the device flow against DIRAC authorization Server. - Scope must have exactly up to one ``group`` (otherwise default) and - one or more ``property`` scope. - If no property, then get default one. + + Scope details: + + + * + If only VO is provided: Uses the default group and its properties for the VO. + + * + If VO and group are provided: Uses the specified group and its properties for the VO. + + * + If VO and properties are provided: Uses the default group and combines its properties with + the + provided properties. + + * + If VO, group, and properties are provided: Uses the specified group and combines its + properties with the + provided properties. Offers the user to go with the browser to ``auth//device?user_code=XYZ``. @@ -1457,9 +1473,9 @@ def userinfo(self, **kwargs: Any) -> _models.UserInfoResponse: def authorization_flow( self, *, - response_type: Union[str, _models.Enum0], + response_type: str, code_challenge: str, - code_challenge_method: Union[str, _models.Enum1], + code_challenge_method: str, client_id: str, redirect_uri: str, scope: str, @@ -1472,16 +1488,35 @@ def authorization_flow( It will redirect to the actual OpenID server (IAM, CheckIn) to perform a authorization code flow. + Scope details: + + + * + If only VO is provided: Uses the default group and its properties for the VO. + + * + If VO and group are provided: Uses the specified group and its properties for the VO. + + * + If VO and properties are provided: Uses the default group and combines its properties with + the + provided properties. + + * + If VO, group, and properties are provided: Uses the specified group and combines its + properties with the + provided properties. + We set the user details obtained from the user authorize flow in a cookie to be able to map the authorization flow with the corresponding user authorize flow. - :keyword response_type: "code" Required. - :paramtype response_type: str or ~generated.models.Enum0 + :keyword response_type: Required. + :paramtype response_type: str :keyword code_challenge: Required. :paramtype code_challenge: str - :keyword code_challenge_method: "S256" Required. - :paramtype code_challenge_method: str or ~generated.models.Enum1 + :keyword code_challenge_method: Required. + :paramtype code_challenge_method: str :keyword client_id: Required. :paramtype client_id: str :keyword redirect_uri: Required. diff --git a/diracx-core/pyproject.toml b/diracx-core/pyproject.toml index 0c09148a..c9cb8f9e 100644 --- a/diracx-core/pyproject.toml +++ b/diracx-core/pyproject.toml @@ -19,7 +19,7 @@ dependencies = [ "cachetools", "email_validator", "gitpython", - "pydantic >=2", + "pydantic >=2.10", "pydantic-settings", "pyyaml", ] diff --git a/diracx-core/src/diracx/core/config/__init__.py b/diracx-core/src/diracx/core/config/__init__.py index 8484944b..60a435ee 100644 --- a/diracx-core/src/diracx/core/config/__init__.py +++ b/diracx-core/src/diracx/core/config/__init__.py @@ -41,9 +41,12 @@ def _apply_default_scheme(value: str) -> str: return value -ConfigSourceUrl = Annotated[ - AnyUrl, UrlConstraints(host_required=False), BeforeValidator(_apply_default_scheme) -] +class AnyUrlWithoutHost(AnyUrl): + + _constraints = UrlConstraints(host_required=False) + + +ConfigSourceUrl = Annotated[AnyUrlWithoutHost, BeforeValidator(_apply_default_scheme)] class ConfigSource(metaclass=ABCMeta): diff --git a/diracx-core/src/diracx/core/settings.py b/diracx-core/src/diracx/core/settings.py index 6e8ec11c..499c533c 100644 --- a/diracx-core/src/diracx/core/settings.py +++ b/diracx-core/src/diracx/core/settings.py @@ -13,14 +13,23 @@ from authlib.jose import JsonWebKey from cryptography.fernet import Fernet -from pydantic import AnyUrl, BeforeValidator, SecretStr, TypeAdapter, UrlConstraints +from pydantic import ( + AnyUrl, + BeforeValidator, + FileUrl, + SecretStr, + TypeAdapter, + UrlConstraints, +) from pydantic_settings import BaseSettings, SettingsConfigDict T = TypeVar("T") -SqlalchemyDsn = Annotated[ - AnyUrl, UrlConstraints(allowed_schemes={"sqlite+aiosqlite", "mysql+aiomysql"}) -] + +class SqlalchemyDsn(AnyUrl): + _constraints = UrlConstraints( + allowed_schemes=["sqlite+aiosqlite", "mysql+aiomysql"] + ) class _TokenSigningKey(SecretStr): @@ -63,9 +72,7 @@ def _apply_default_scheme(value: str) -> str: return value -LocalFileUrl = Annotated[ - AnyUrl, UrlConstraints(host_required=False), BeforeValidator(_apply_default_scheme) -] +LocalFileUrl = Annotated[FileUrl, BeforeValidator(_apply_default_scheme)] class ServiceSettingsBase(BaseSettings): diff --git a/diracx-db/pyproject.toml b/diracx-db/pyproject.toml index ed8309cc..fc4ec487 100644 --- a/diracx-db/pyproject.toml +++ b/diracx-db/pyproject.toml @@ -17,7 +17,7 @@ dependencies = [ "diracx-core", "fastapi", "opensearch-py[async]", - "pydantic >=2.4", + "pydantic >=2.10", "sqlalchemy[aiomysql,aiosqlite] >= 2", ] dynamic = ["version"] diff --git a/diracx-routers/pyproject.toml b/diracx-routers/pyproject.toml index 91d99023..c72bc191 100644 --- a/diracx-routers/pyproject.toml +++ b/diracx-routers/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "python-multipart", "fastapi", "httpx", - "pydantic >=2.4", + "pydantic >=2.10", "uvicorn", "sqlalchemy", "opentelemetry-api", diff --git a/diracx-routers/src/diracx/routers/__init__.py b/diracx-routers/src/diracx/routers/__init__.py index baa99784..b3725b2f 100644 --- a/diracx-routers/src/diracx/routers/__init__.py +++ b/diracx-routers/src/diracx/routers/__init__.py @@ -54,7 +54,7 @@ logger = logging.getLogger(__name__) -DIRACX_MIN_CLIENT_VERSION = "0.0.1" +DIRACX_MIN_CLIENT_VERSION = "0.0.1a1" ###########################################3 @@ -464,13 +464,29 @@ def __init__(self, app: FastAPI): async def dispatch(self, request: Request, call_next) -> Response: client_version = request.headers.get("DiracX-Client-Version") - if client_version and self.is_version_too_old(client_version): - # When comes from Swagger or Web, there is no client version header. - # This is not managed here. - raise HTTPException( - status_code=HTTPStatus.UPGRADE_REQUIRED, - detail=f"Client version ({client_version}) not recent enough (>= {self.min_client_version}). Upgrade.", + + try: + if client_version and self.is_version_too_old(client_version): + # When comes from Swagger or Web, there is no client version header. + # This is not managed here. + + raise HTTPException( + status_code=HTTPStatus.UPGRADE_REQUIRED, + detail=f"Client version ({client_version})" + f"not recent enough (>= {self.min_client_version})." + "Upgrade.", + ) + except HTTPException as exc: + # Return a JSONResponse because the HTTPException + # is not handled nicely in the middleware + logger.error("Error checking client version %s", client_version) + return JSONResponse( + status_code=exc.status_code, + content={"detail": exc.detail}, ) + # If the version is not given + except Exception: # noqa: S110 + pass response = await call_next(request) return response diff --git a/diracx-routers/src/diracx/routers/fastapi_classes.py b/diracx-routers/src/diracx/routers/fastapi_classes.py index 80a2ac09..71960f22 100644 --- a/diracx-routers/src/diracx/routers/fastapi_classes.py +++ b/diracx-routers/src/diracx/routers/fastapi_classes.py @@ -22,6 +22,10 @@ def _downgrade_openapi_schema(data): data |= v[0] elif k == "const": data.pop(k) + # https://github.com/fastapi/fastapi/discussions/12984 + elif k == "propertyNames": + data.pop(k) + _downgrade_openapi_schema(v) if isinstance(data, list): for v in data: diff --git a/diracx-routers/src/diracx/routers/job_manager/__init__.py b/diracx-routers/src/diracx/routers/job_manager/__init__.py index 5dd9f7d4..ce563655 100644 --- a/diracx-routers/src/diracx/routers/job_manager/__init__.py +++ b/diracx-routers/src/diracx/routers/job_manager/__init__.py @@ -773,10 +773,27 @@ async def get_single_job_status( return {job_id: status} +EXAMPLE_SINGLE_JOB_STATUS = { + "Single Job Status": { + "summary": "Set single job status", + "description": "Send status for the job", + "value": { + "status": { + "2024-11-22T16:02:25.541624+00:00": {"Status": "Running"}, + "2024-11-22T17:02:25.541624+00:00": {"Status": "Killed"}, + } + }, + }, +} + + @router.patch("/{job_id}/status") async def set_single_job_status( job_id: int, - status: Annotated[dict[datetime, JobStatusUpdate], Body()], + status: Annotated[ + dict[datetime, JobStatusUpdate], + Body(openapi_examples=EXAMPLE_SINGLE_JOB_STATUS), + ], job_db: JobDB, job_logging_db: JobLoggingDB, check_permissions: CheckWMSPolicyCallable, diff --git a/diracx-routers/src/diracx/routers/job_manager/sandboxes.py b/diracx-routers/src/diracx/routers/job_manager/sandboxes.py index 5bf474b2..24f4ed95 100644 --- a/diracx-routers/src/diracx/routers/job_manager/sandboxes.py +++ b/diracx-routers/src/diracx/routers/job_manager/sandboxes.py @@ -55,7 +55,7 @@ class SandboxStoreSettings(ServiceSettingsBase): auto_create_bucket: bool = False url_validity_seconds: int = 5 * 60 se_name: str = "SandboxSE" - _client: S3Client = PrivateAttr(None) + _client: S3Client = PrivateAttr() @contextlib.asynccontextmanager async def lifetime_function(self) -> AsyncIterator[None]: diff --git a/diracx-routers/tests/test_generic.py b/diracx-routers/tests/test_generic.py index 87b2c3bb..a83ea439 100644 --- a/diracx-routers/tests/test_generic.py +++ b/diracx-routers/tests/test_generic.py @@ -1,7 +1,6 @@ from http import HTTPStatus import pytest -from fastapi import HTTPException from packaging.version import Version, parse from diracx.routers import DIRACX_MIN_CLIENT_VERSION @@ -59,15 +58,14 @@ def test_min_client_version_lower_than_expected(test_client): lower_version_than_min: Version = ( f"{min_client_version.major}.{min_client_version.minor}.dev123" ) - with pytest.raises(HTTPException) as response: - test_client.get("/", headers={"DiracX-Client-Version": lower_version_than_min}) - assert response.value.status_code == HTTPStatus.UPGRADE_REQUIRED - assert str(min_client_version) in response.value.detail + + r = test_client.get("/", headers={"DiracX-Client-Version": lower_version_than_min}) + assert r.status_code == HTTPStatus.UPGRADE_REQUIRED + assert str(min_client_version) in r.json()["detail"] def test_invalid_client_version(test_client, caplog: pytest.LogCaptureFixture): invalid_version = "invalid.version" - with pytest.raises(HTTPException) as response: - test_client.get("/", headers={"DiracX-Client-Version": invalid_version}) - assert response.value.status_code == 400 - assert invalid_version in response.value.detail + r = test_client.get("/", headers={"DiracX-Client-Version": invalid_version}) + assert r.status_code == 400 + assert invalid_version in r.json()["detail"]