From 6e32eb8d6304224f8555adf3de0a9beae2993e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 12 Dec 2023 14:55:06 +0100 Subject: [PATCH 1/9] Migrate to python-generator --- jellyfish/__init__.py | 45 +- jellyfish/_openapi_client/__init__.py | 76 +- jellyfish/_openapi_client/api/__init__.py | 7 +- jellyfish/_openapi_client/api/hls/__init__.py | 0 .../api/hls/get_hls_content.py | 244 ++++ .../api/hls/subscribe_tracks.py | 177 +++ jellyfish/_openapi_client/api/hls_api.py | 435 ------ .../_openapi_client/api/recording/__init__.py | 0 .../api/recording/delete_recording.py | 159 ++ .../api/recording/get_recording_content.py | 173 +++ .../api/recording/get_recordings.py | 131 ++ .../_openapi_client/api/recording_api.py | 484 ------ .../_openapi_client/api/room/__init__.py | 0 .../_openapi_client/api/room/add_component.py | 183 +++ .../_openapi_client/api/room/add_peer.py | 187 +++ .../_openapi_client/api/room/create_room.py | 164 +++ .../api/room/delete_component.py | 173 +++ .../_openapi_client/api/room/delete_peer.py | 173 +++ .../_openapi_client/api/room/delete_room.py | 159 ++ .../_openapi_client/api/room/get_all_rooms.py | 131 ++ .../_openapi_client/api/room/get_room.py | 161 ++ jellyfish/_openapi_client/api/room_api.py | 1292 ----------------- jellyfish/_openapi_client/api_client.py | 835 ----------- jellyfish/_openapi_client/api_response.py | 26 - jellyfish/_openapi_client/client.py | 274 ++++ jellyfish/_openapi_client/configuration.py | 458 ------ jellyfish/_openapi_client/errors.py | 14 + jellyfish/_openapi_client/exceptions.py | 157 -- jellyfish/_openapi_client/models/__init__.py | 113 +- .../models/add_component_json_body.py | 130 ++ .../models/add_component_request.py | 77 - .../models/add_peer_json_body.py | 72 + .../models/add_peer_request.py | 76 - jellyfish/_openapi_client/models/component.py | 188 --- .../models/component_details_response.py | 143 +- .../_openapi_client/models/component_file.py | 66 + .../_openapi_client/models/component_hls.py | 120 +- .../models/component_metadata_hls.py | 112 -- .../models/component_options.py | 159 -- .../models/component_options_file.py | 60 + .../models/component_options_hls.py | 228 ++- .../component_options_hls_subscribe_mode.py | 9 + .../models/component_options_hlss3.py | 149 -- .../models/component_options_rtsp.py | 172 +-- .../models/component_properties_hls.py | 93 ++ ...component_properties_hls_subscribe_mode.py | 9 + .../models/component_properties_rtsp.py | 44 + .../_openapi_client/models/component_rtsp.py | 115 +- jellyfish/_openapi_client/models/error.py | 89 +- jellyfish/_openapi_client/models/hls_skip.py | 32 +- jellyfish/_openapi_client/models/peer.py | 109 +- .../models/peer_details_response.py | 105 +- .../models/peer_details_response_data.py | 112 +- .../_openapi_client/models/peer_options.py | 143 -- .../models/peer_options_web_rtc.py | 98 +- .../_openapi_client/models/peer_status.py | 30 +- .../models/recording_list_response.py | 90 +- jellyfish/_openapi_client/models/room.py | 213 +-- .../_openapi_client/models/room_config.py | 169 +-- .../models/room_config_video_codec.py | 9 + .../models/room_create_details_response.py | 107 +- .../room_create_details_response_data.py | 116 +- .../models/room_details_response.py | 103 +- .../models/rooms_listing_response.py | 115 +- .../_openapi_client/models/s3_credentials.py | 137 +- .../models/subscription_config.py | 92 +- jellyfish/_openapi_client/py.typed | 1 + jellyfish/_openapi_client/rest.py | 401 ----- jellyfish/_openapi_client/types.py | 44 + jellyfish/_recording_api.py | 22 +- jellyfish/_room_api.py | 88 +- jellyfish/_ws_notifier.py | 9 +- jellyfish/events/__init__.py | 15 +- openapi-python-client-config.yaml | 2 + openapi.yaml | 977 +++++++++++++ poetry.lock | 520 +++++-- pyproject.toml | 3 +- tests/test_notifier.py | 14 +- tests/test_recording_api.py | 5 +- tests/test_room_api.py | 51 +- 80 files changed, 5854 insertions(+), 6620 deletions(-) create mode 100644 jellyfish/_openapi_client/api/hls/__init__.py create mode 100644 jellyfish/_openapi_client/api/hls/get_hls_content.py create mode 100644 jellyfish/_openapi_client/api/hls/subscribe_tracks.py delete mode 100644 jellyfish/_openapi_client/api/hls_api.py create mode 100644 jellyfish/_openapi_client/api/recording/__init__.py create mode 100644 jellyfish/_openapi_client/api/recording/delete_recording.py create mode 100644 jellyfish/_openapi_client/api/recording/get_recording_content.py create mode 100644 jellyfish/_openapi_client/api/recording/get_recordings.py delete mode 100644 jellyfish/_openapi_client/api/recording_api.py create mode 100644 jellyfish/_openapi_client/api/room/__init__.py create mode 100644 jellyfish/_openapi_client/api/room/add_component.py create mode 100644 jellyfish/_openapi_client/api/room/add_peer.py create mode 100644 jellyfish/_openapi_client/api/room/create_room.py create mode 100644 jellyfish/_openapi_client/api/room/delete_component.py create mode 100644 jellyfish/_openapi_client/api/room/delete_peer.py create mode 100644 jellyfish/_openapi_client/api/room/delete_room.py create mode 100644 jellyfish/_openapi_client/api/room/get_all_rooms.py create mode 100644 jellyfish/_openapi_client/api/room/get_room.py delete mode 100644 jellyfish/_openapi_client/api/room_api.py delete mode 100644 jellyfish/_openapi_client/api_client.py delete mode 100644 jellyfish/_openapi_client/api_response.py create mode 100644 jellyfish/_openapi_client/client.py delete mode 100644 jellyfish/_openapi_client/configuration.py create mode 100644 jellyfish/_openapi_client/errors.py delete mode 100644 jellyfish/_openapi_client/exceptions.py create mode 100644 jellyfish/_openapi_client/models/add_component_json_body.py delete mode 100644 jellyfish/_openapi_client/models/add_component_request.py create mode 100644 jellyfish/_openapi_client/models/add_peer_json_body.py delete mode 100644 jellyfish/_openapi_client/models/add_peer_request.py delete mode 100644 jellyfish/_openapi_client/models/component.py create mode 100644 jellyfish/_openapi_client/models/component_file.py delete mode 100644 jellyfish/_openapi_client/models/component_metadata_hls.py delete mode 100644 jellyfish/_openapi_client/models/component_options.py create mode 100644 jellyfish/_openapi_client/models/component_options_file.py create mode 100644 jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py delete mode 100644 jellyfish/_openapi_client/models/component_options_hlss3.py create mode 100644 jellyfish/_openapi_client/models/component_properties_hls.py create mode 100644 jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py create mode 100644 jellyfish/_openapi_client/models/component_properties_rtsp.py delete mode 100644 jellyfish/_openapi_client/models/peer_options.py create mode 100644 jellyfish/_openapi_client/models/room_config_video_codec.py delete mode 100644 jellyfish/_openapi_client/rest.py create mode 100644 jellyfish/_openapi_client/types.py create mode 100644 openapi-python-client-config.yaml create mode 100644 openapi.yaml diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index 2bc93fd..b5ef76b 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -4,37 +4,29 @@ # pylint: disable=locally-disabled, no-name-in-module, import-error -from pydantic.error_wrappers import ValidationError - -# API -from jellyfish._room_api import RoomApi -from jellyfish._recording_api import RecordingApi -from jellyfish._ws_notifier import Notifier -from jellyfish._webhook_notifier import receive_json +# Server Messages +from jellyfish import events # Models -from jellyfish._openapi_client import ( - Room, - RoomConfig, - Peer, - Component, +from jellyfish._openapi_client.models import ( ComponentHLS, - ComponentRTSP, - ComponentOptions, - ComponentOptionsRTSP, ComponentOptionsHLS, + ComponentOptionsHLSSubscribeMode, + ComponentOptionsRTSP, + ComponentRTSP, + Peer, PeerOptionsWebRTC, + Room, + RoomConfig, + RoomConfigVideoCodec, + Error, ) -# Server Messages -from jellyfish import events - -# Exceptions -from jellyfish._openapi_client.exceptions import ( - UnauthorizedException, - NotFoundException, - BadRequestException, -) +# API +from jellyfish._webhook_notifier import receive_json +from jellyfish._ws_notifier import Notifier +from jellyfish._recording_api import RecordingApi +from jellyfish._room_api import RoomApi __all__ = [ @@ -44,18 +36,13 @@ "receive_json", "Room", "Peer", - "Component", "ComponentHLS", "ComponentRTSP", "ComponentOptionsHLS", "RoomConfig", - "ComponentOptions", "ComponentOptionsRTSP", "PeerOptionsWebRTC", "events", - "UnauthorizedException", - "NotFoundException", - "BadRequestException", ] __docformat__ = "restructuredtext" diff --git a/jellyfish/_openapi_client/__init__.py b/jellyfish/_openapi_client/__init__.py index 34855c8..559de5e 100644 --- a/jellyfish/_openapi_client/__init__.py +++ b/jellyfish/_openapi_client/__init__.py @@ -1,73 +1,7 @@ -# coding: utf-8 +""" A client library for accessing Jellyfish Media Server """ +from .client import AuthenticatedClient, Client -# flake8: noqa - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -__version__ = "1.0.0" - -# import apis into sdk package -from jellyfish._openapi_client.api.hls_api import HlsApi -from jellyfish._openapi_client.api.recording_api import RecordingApi -from jellyfish._openapi_client.api.room_api import RoomApi - -# import ApiClient -from jellyfish._openapi_client.api_response import ApiResponse -from jellyfish._openapi_client.api_client import ApiClient -from jellyfish._openapi_client.configuration import Configuration -from jellyfish._openapi_client.exceptions import OpenApiException -from jellyfish._openapi_client.exceptions import ApiTypeError -from jellyfish._openapi_client.exceptions import ApiValueError -from jellyfish._openapi_client.exceptions import ApiKeyError -from jellyfish._openapi_client.exceptions import ApiAttributeError -from jellyfish._openapi_client.exceptions import ApiException - -# import models into sdk package -from jellyfish._openapi_client.models.add_component_request import AddComponentRequest -from jellyfish._openapi_client.models.add_peer_request import AddPeerRequest -from jellyfish._openapi_client.models.component import Component -from jellyfish._openapi_client.models.component_details_response import ( - ComponentDetailsResponse, -) -from jellyfish._openapi_client.models.component_hls import ComponentHLS -from jellyfish._openapi_client.models.component_metadata_hls import ComponentMetadataHLS -from jellyfish._openapi_client.models.component_options import ComponentOptions -from jellyfish._openapi_client.models.component_options_hls import ComponentOptionsHLS -from jellyfish._openapi_client.models.component_options_hlss3 import ( - ComponentOptionsHLSS3, -) -from jellyfish._openapi_client.models.component_options_rtsp import ComponentOptionsRTSP -from jellyfish._openapi_client.models.component_rtsp import ComponentRTSP -from jellyfish._openapi_client.models.error import Error -from jellyfish._openapi_client.models.hls_skip import HlsSkip -from jellyfish._openapi_client.models.peer import Peer -from jellyfish._openapi_client.models.peer_details_response import PeerDetailsResponse -from jellyfish._openapi_client.models.peer_details_response_data import ( - PeerDetailsResponseData, -) -from jellyfish._openapi_client.models.peer_options import PeerOptions -from jellyfish._openapi_client.models.peer_options_web_rtc import PeerOptionsWebRTC -from jellyfish._openapi_client.models.peer_status import PeerStatus -from jellyfish._openapi_client.models.recording_list_response import ( - RecordingListResponse, -) -from jellyfish._openapi_client.models.room import Room -from jellyfish._openapi_client.models.room_config import RoomConfig -from jellyfish._openapi_client.models.room_create_details_response import ( - RoomCreateDetailsResponse, -) -from jellyfish._openapi_client.models.room_create_details_response_data import ( - RoomCreateDetailsResponseData, +__all__ = ( + "AuthenticatedClient", + "Client", ) -from jellyfish._openapi_client.models.room_details_response import RoomDetailsResponse -from jellyfish._openapi_client.models.rooms_listing_response import RoomsListingResponse -from jellyfish._openapi_client.models.s3_credentials import S3Credentials -from jellyfish._openapi_client.models.subscription_config import SubscriptionConfig diff --git a/jellyfish/_openapi_client/api/__init__.py b/jellyfish/_openapi_client/api/__init__.py index 4d0419d..dc035f4 100644 --- a/jellyfish/_openapi_client/api/__init__.py +++ b/jellyfish/_openapi_client/api/__init__.py @@ -1,6 +1 @@ -# flake8: noqa - -# import apis into api package -from jellyfish._openapi_client.api.hls_api import HlsApi -from jellyfish._openapi_client.api.recording_api import RecordingApi -from jellyfish._openapi_client.api.room_api import RoomApi +""" Contains methods for accessing the API """ diff --git a/jellyfish/_openapi_client/api/hls/__init__.py b/jellyfish/_openapi_client/api/hls/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jellyfish/_openapi_client/api/hls/get_hls_content.py b/jellyfish/_openapi_client/api/hls/get_hls_content.py new file mode 100644 index 0000000..8887a32 --- /dev/null +++ b/jellyfish/_openapi_client/api/hls/get_hls_content.py @@ -0,0 +1,244 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...models.hls_skip import HlsSkip +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + room_id: str, + filename: str, + *, + field_hls_msn: Union[Unset, None, int] = UNSET, + field_hls_part: Union[Unset, None, int] = UNSET, + field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + range_: Union[Unset, str] = UNSET, +) -> Dict[str, Any]: + headers = {} + if not isinstance(range_, Unset): + headers["range"] = range_ + + params: Dict[str, Any] = {} + params["_HLS_msn"] = field_hls_msn + + params["_HLS_part"] = field_hls_part + + json_field_hls_skip: Union[Unset, None, str] = UNSET + if not isinstance(field_hls_skip, Unset): + json_field_hls_skip = field_hls_skip.value if field_hls_skip else None + + params["_HLS_skip"] = json_field_hls_skip + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + return { + "method": "get", + "url": "/hls/{room_id}/{filename}".format( + room_id=room_id, + filename=filename, + ), + "params": params, + "headers": headers, + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, str]]: + if response.status_code == HTTPStatus.OK: + response_200 = cast(str, response.json()) + return response_200 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, str]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], + field_hls_msn: Union[Unset, None, int] = UNSET, + field_hls_part: Union[Unset, None, int] = UNSET, + field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + range_: Union[Unset, str] = UNSET, +) -> Response[Union[Error, str]]: + """Retrieve HLS Content + + Args: + room_id (str): + filename (str): + field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. + field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. + field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + range_ (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, str]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + filename=filename, + field_hls_msn=field_hls_msn, + field_hls_part=field_hls_part, + field_hls_skip=field_hls_skip, + range_=range_, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], + field_hls_msn: Union[Unset, None, int] = UNSET, + field_hls_part: Union[Unset, None, int] = UNSET, + field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + range_: Union[Unset, str] = UNSET, +) -> Optional[Union[Error, str]]: + """Retrieve HLS Content + + Args: + room_id (str): + filename (str): + field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. + field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. + field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + range_ (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, str] + """ + + return sync_detailed( + room_id=room_id, + filename=filename, + client=client, + field_hls_msn=field_hls_msn, + field_hls_part=field_hls_part, + field_hls_skip=field_hls_skip, + range_=range_, + ).parsed + + +async def asyncio_detailed( + room_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], + field_hls_msn: Union[Unset, None, int] = UNSET, + field_hls_part: Union[Unset, None, int] = UNSET, + field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + range_: Union[Unset, str] = UNSET, +) -> Response[Union[Error, str]]: + """Retrieve HLS Content + + Args: + room_id (str): + filename (str): + field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. + field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. + field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + range_ (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, str]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + filename=filename, + field_hls_msn=field_hls_msn, + field_hls_part=field_hls_part, + field_hls_skip=field_hls_skip, + range_=range_, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], + field_hls_msn: Union[Unset, None, int] = UNSET, + field_hls_part: Union[Unset, None, int] = UNSET, + field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + range_: Union[Unset, str] = UNSET, +) -> Optional[Union[Error, str]]: + """Retrieve HLS Content + + Args: + room_id (str): + filename (str): + field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. + field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. + field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + range_ (Union[Unset, str]): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, str] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + filename=filename, + client=client, + field_hls_msn=field_hls_msn, + field_hls_part=field_hls_part, + field_hls_skip=field_hls_skip, + range_=range_, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/hls/subscribe_tracks.py b/jellyfish/_openapi_client/api/hls/subscribe_tracks.py new file mode 100644 index 0000000..c963f34 --- /dev/null +++ b/jellyfish/_openapi_client/api/hls/subscribe_tracks.py @@ -0,0 +1,177 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...models.subscription_config import SubscriptionConfig +from ...types import Response + + +def _get_kwargs( + room_id: str, + *, + json_body: SubscriptionConfig, +) -> Dict[str, Any]: + pass + + json_json_body = json_body.to_dict() + + return { + "method": "post", + "url": "/hls/{room_id}/subscribe".format( + room_id=room_id, + ), + "json": json_json_body, + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Error]]: + if response.status_code == HTTPStatus.CREATED: + response_201 = cast(Any, None) + return response_201 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: SubscriptionConfig, +) -> Response[Union[Any, Error]]: + """Subscribe hls component for tracks + + Args: + room_id (str): + json_body (SubscriptionConfig): Subscription config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + json_body=json_body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: SubscriptionConfig, +) -> Optional[Union[Any, Error]]: + """Subscribe hls component for tracks + + Args: + room_id (str): + json_body (SubscriptionConfig): Subscription config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return sync_detailed( + room_id=room_id, + client=client, + json_body=json_body, + ).parsed + + +async def asyncio_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: SubscriptionConfig, +) -> Response[Union[Any, Error]]: + """Subscribe hls component for tracks + + Args: + room_id (str): + json_body (SubscriptionConfig): Subscription config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + json_body=json_body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: SubscriptionConfig, +) -> Optional[Union[Any, Error]]: + """Subscribe hls component for tracks + + Args: + room_id (str): + json_body (SubscriptionConfig): Subscription config + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + client=client, + json_body=json_body, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/hls_api.py b/jellyfish/_openapi_client/api/hls_api.py deleted file mode 100644 index db66759..0000000 --- a/jellyfish/_openapi_client/api/hls_api.py +++ /dev/null @@ -1,435 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import re # noqa: F401 -import io -import warnings - -from pydantic import validate_arguments, ValidationError -from typing_extensions import Annotated - -from pydantic import Field, StrictStr, conint - -from typing import Optional - -from jellyfish._openapi_client.models.hls_skip import HlsSkip -from jellyfish._openapi_client.models.subscription_config import SubscriptionConfig - -from jellyfish._openapi_client.api_client import ApiClient -from jellyfish._openapi_client.api_response import ApiResponse -from jellyfish._openapi_client.exceptions import ( # noqa: F401 - ApiTypeError, - ApiValueError, -) - - -class HlsApi(object): - """NOTE: This class is auto generated by OpenAPI Generator - Ref: https://openapi-generator.tech - - Do not edit the class manually. - """ - - def __init__(self, api_client=None): - if api_client is None: - api_client = ApiClient.get_default() - self.api_client = api_client - - @validate_arguments - def get_hls_content( - self, - room_id: Annotated[StrictStr, Field(..., description="Room id")], - filename: Annotated[StrictStr, Field(..., description="Name of the file")], - range: Annotated[ - Optional[StrictStr], Field(description="Byte range of partial segment") - ] = None, - hls_msn: Annotated[ - Optional[conint(strict=True, ge=0)], - Field(description="Segment sequence number"), - ] = None, - hls_part: Annotated[ - Optional[conint(strict=True, ge=0)], - Field(description="Partial segment sequence number"), - ] = None, - hls_skip: Annotated[ - Optional[HlsSkip], Field(description="Is delta manifest requested") - ] = None, - **kwargs - ) -> str: # noqa: E501 - """Retrieve HLS Content # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_hls_content(room_id, filename, range, hls_msn, hls_part, hls_skip, async_req=True) - >>> result = thread.get() - - :param room_id: Room id (required) - :type room_id: str - :param filename: Name of the file (required) - :type filename: str - :param range: Byte range of partial segment - :type range: str - :param hls_msn: Segment sequence number - :type hls_msn: int - :param hls_part: Partial segment sequence number - :type hls_part: int - :param hls_skip: Is delta manifest requested - :type hls_skip: HlsSkip - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: str - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the get_hls_content_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.get_hls_content_with_http_info( - room_id, filename, range, hls_msn, hls_part, hls_skip, **kwargs - ) # noqa: E501 - - @validate_arguments - def get_hls_content_with_http_info( - self, - room_id: Annotated[StrictStr, Field(..., description="Room id")], - filename: Annotated[StrictStr, Field(..., description="Name of the file")], - range: Annotated[ - Optional[StrictStr], Field(description="Byte range of partial segment") - ] = None, - hls_msn: Annotated[ - Optional[conint(strict=True, ge=0)], - Field(description="Segment sequence number"), - ] = None, - hls_part: Annotated[ - Optional[conint(strict=True, ge=0)], - Field(description="Partial segment sequence number"), - ] = None, - hls_skip: Annotated[ - Optional[HlsSkip], Field(description="Is delta manifest requested") - ] = None, - **kwargs - ) -> ApiResponse: # noqa: E501 - """Retrieve HLS Content # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_hls_content_with_http_info(room_id, filename, range, hls_msn, hls_part, hls_skip, async_req=True) - >>> result = thread.get() - - :param room_id: Room id (required) - :type room_id: str - :param filename: Name of the file (required) - :type filename: str - :param range: Byte range of partial segment - :type range: str - :param hls_msn: Segment sequence number - :type hls_msn: int - :param hls_part: Partial segment sequence number - :type hls_part: int - :param hls_skip: Is delta manifest requested - :type hls_skip: HlsSkip - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(str, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = [ - "room_id", - "filename", - "range", - "hls_msn", - "hls_part", - "hls_skip", - ] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method get_hls_content" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - if _params["filename"]: - _path_params["filename"] = _params["filename"] - - # process the query parameters - _query_params = [] - if _params.get("hls_msn") is not None: # noqa: E501 - _query_params.append(("_HLS_msn", _params["hls_msn"])) - - if _params.get("hls_part") is not None: # noqa: E501 - _query_params.append(("_HLS_part", _params["hls_part"])) - - if _params.get("hls_skip") is not None: # noqa: E501 - _query_params.append(("_HLS_skip", _params["hls_skip"].value)) - - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - if _params["range"]: - _header_params["range"] = _params["range"] - - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "200": "str", - "404": "Error", - } - - return self.api_client.call_api( - "/hls/{room_id}/{filename}", - "GET", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def subscribe_tracks( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - subscription_config: Annotated[ - Optional[SubscriptionConfig], Field(description="Subscribe configuration") - ] = None, - **kwargs - ) -> None: # noqa: E501 - """Subscribe hls component for tracks # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.subscribe_tracks(room_id, subscription_config, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param subscription_config: Subscribe configuration - :type subscription_config: SubscriptionConfig - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the subscribe_tracks_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.subscribe_tracks_with_http_info( - room_id, subscription_config, **kwargs - ) # noqa: E501 - - @validate_arguments - def subscribe_tracks_with_http_info( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - subscription_config: Annotated[ - Optional[SubscriptionConfig], Field(description="Subscribe configuration") - ] = None, - **kwargs - ) -> ApiResponse: # noqa: E501 - """Subscribe hls component for tracks # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.subscribe_tracks_with_http_info(room_id, subscription_config, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param subscription_config: Subscribe configuration - :type subscription_config: SubscriptionConfig - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - - _params = locals() - - _all_params = ["room_id", "subscription_config"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method subscribe_tracks" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - if _params["subscription_config"] is not None: - _body_params = _params["subscription_config"] - - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # set the HTTP header `Content-Type` - _content_types_list = _params.get( - "_content_type", - self.api_client.select_header_content_type(["application/json"]), - ) - if _content_types_list: - _header_params["Content-Type"] = _content_types_list - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = {} - - return self.api_client.call_api( - "/hls/{room_id}/subscribe", - "POST", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) diff --git a/jellyfish/_openapi_client/api/recording/__init__.py b/jellyfish/_openapi_client/api/recording/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jellyfish/_openapi_client/api/recording/delete_recording.py b/jellyfish/_openapi_client/api/recording/delete_recording.py new file mode 100644 index 0000000..51bc34a --- /dev/null +++ b/jellyfish/_openapi_client/api/recording/delete_recording.py @@ -0,0 +1,159 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + recording_id: str, +) -> Dict[str, Any]: + pass + + return { + "method": "delete", + "url": "/recording/{recording_id}".format( + recording_id=recording_id, + ), + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Error]]: + if response.status_code == HTTPStatus.NO_CONTENT: + response_204 = cast(Any, None) + return response_204 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + recording_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Deletes the recording + + Args: + recording_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + recording_id=recording_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + recording_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Deletes the recording + + Args: + recording_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return sync_detailed( + recording_id=recording_id, + client=client, + ).parsed + + +async def asyncio_detailed( + recording_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Deletes the recording + + Args: + recording_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + recording_id=recording_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + recording_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Deletes the recording + + Args: + recording_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return ( + await asyncio_detailed( + recording_id=recording_id, + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/recording/get_recording_content.py b/jellyfish/_openapi_client/api/recording/get_recording_content.py new file mode 100644 index 0000000..56ced1b --- /dev/null +++ b/jellyfish/_openapi_client/api/recording/get_recording_content.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + recording_id: str, + filename: str, +) -> Dict[str, Any]: + pass + + return { + "method": "get", + "url": "/recording/{recording_id}/{filename}".format( + recording_id=recording_id, + filename=filename, + ), + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, str]]: + if response.status_code == HTTPStatus.OK: + response_200 = cast(str, response.json()) + return response_200 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, str]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + recording_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, str]]: + """Retrieve Recording (HLS) Content + + Args: + recording_id (str): + filename (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, str]] + """ + + kwargs = _get_kwargs( + recording_id=recording_id, + filename=filename, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + recording_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, str]]: + """Retrieve Recording (HLS) Content + + Args: + recording_id (str): + filename (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, str] + """ + + return sync_detailed( + recording_id=recording_id, + filename=filename, + client=client, + ).parsed + + +async def asyncio_detailed( + recording_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, str]]: + """Retrieve Recording (HLS) Content + + Args: + recording_id (str): + filename (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, str]] + """ + + kwargs = _get_kwargs( + recording_id=recording_id, + filename=filename, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + recording_id: str, + filename: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, str]]: + """Retrieve Recording (HLS) Content + + Args: + recording_id (str): + filename (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, str] + """ + + return ( + await asyncio_detailed( + recording_id=recording_id, + filename=filename, + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/recording/get_recordings.py b/jellyfish/_openapi_client/api/recording/get_recordings.py new file mode 100644 index 0000000..99bf969 --- /dev/null +++ b/jellyfish/_openapi_client/api/recording/get_recordings.py @@ -0,0 +1,131 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...models.recording_list_response import RecordingListResponse +from ...types import Response + + +def _get_kwargs() -> Dict[str, Any]: + pass + + return { + "method": "get", + "url": "/recording", + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, RecordingListResponse]]: + if response.status_code == HTTPStatus.OK: + response_200 = RecordingListResponse.from_dict(response.json()) + + return response_200 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, RecordingListResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, RecordingListResponse]]: + """Lists all available recordings + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RecordingListResponse]] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, RecordingListResponse]]: + """Lists all available recordings + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RecordingListResponse] + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, RecordingListResponse]]: + """Lists all available recordings + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RecordingListResponse]] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, RecordingListResponse]]: + """Lists all available recordings + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RecordingListResponse] + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/recording_api.py b/jellyfish/_openapi_client/api/recording_api.py deleted file mode 100644 index bfa91a9..0000000 --- a/jellyfish/_openapi_client/api/recording_api.py +++ /dev/null @@ -1,484 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import re # noqa: F401 -import io -import warnings - -from pydantic import validate_arguments, ValidationError -from typing_extensions import Annotated - -from pydantic import Field, StrictStr - -from jellyfish._openapi_client.models.recording_list_response import ( - RecordingListResponse, -) - -from jellyfish._openapi_client.api_client import ApiClient -from jellyfish._openapi_client.api_response import ApiResponse -from jellyfish._openapi_client.exceptions import ( # noqa: F401 - ApiTypeError, - ApiValueError, -) - - -class RecordingApi(object): - """NOTE: This class is auto generated by OpenAPI Generator - Ref: https://openapi-generator.tech - - Do not edit the class manually. - """ - - def __init__(self, api_client=None): - if api_client is None: - api_client = ApiClient.get_default() - self.api_client = api_client - - @validate_arguments - def delete_recording( - self, - recording_id: Annotated[StrictStr, Field(..., description="Recording id")], - **kwargs - ) -> None: # noqa: E501 - """Deletes the recording # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_recording(recording_id, async_req=True) - >>> result = thread.get() - - :param recording_id: Recording id (required) - :type recording_id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the delete_recording_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.delete_recording_with_http_info( - recording_id, **kwargs - ) # noqa: E501 - - @validate_arguments - def delete_recording_with_http_info( - self, - recording_id: Annotated[StrictStr, Field(..., description="Recording id")], - **kwargs - ) -> ApiResponse: # noqa: E501 - """Deletes the recording # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_recording_with_http_info(recording_id, async_req=True) - >>> result = thread.get() - - :param recording_id: Recording id (required) - :type recording_id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - - _params = locals() - - _all_params = ["recording_id"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method delete_recording" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["recording_id"]: - _path_params["recording_id"] = _params["recording_id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = {} - - return self.api_client.call_api( - "/recording/{recording_id}", - "DELETE", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def get_recording_content( - self, - recording_id: Annotated[StrictStr, Field(..., description="Recording id")], - filename: Annotated[StrictStr, Field(..., description="Name of the file")], - **kwargs - ) -> str: # noqa: E501 - """Retrieve Recording (HLS) Content # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_recording_content(recording_id, filename, async_req=True) - >>> result = thread.get() - - :param recording_id: Recording id (required) - :type recording_id: str - :param filename: Name of the file (required) - :type filename: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: str - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the get_recording_content_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.get_recording_content_with_http_info( - recording_id, filename, **kwargs - ) # noqa: E501 - - @validate_arguments - def get_recording_content_with_http_info( - self, - recording_id: Annotated[StrictStr, Field(..., description="Recording id")], - filename: Annotated[StrictStr, Field(..., description="Name of the file")], - **kwargs - ) -> ApiResponse: # noqa: E501 - """Retrieve Recording (HLS) Content # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_recording_content_with_http_info(recording_id, filename, async_req=True) - >>> result = thread.get() - - :param recording_id: Recording id (required) - :type recording_id: str - :param filename: Name of the file (required) - :type filename: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(str, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = ["recording_id", "filename"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method get_recording_content" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["recording_id"]: - _path_params["recording_id"] = _params["recording_id"] - - if _params["filename"]: - _path_params["filename"] = _params["filename"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "200": "str", - "404": "Error", - } - - return self.api_client.call_api( - "/recording/{recording_id}/{filename}", - "GET", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def get_recordings(self, **kwargs) -> RecordingListResponse: # noqa: E501 - """Lists all available recordings # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_recordings(async_req=True) - >>> result = thread.get() - - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: RecordingListResponse - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the get_recordings_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.get_recordings_with_http_info(**kwargs) # noqa: E501 - - @validate_arguments - def get_recordings_with_http_info(self, **kwargs) -> ApiResponse: # noqa: E501 - """Lists all available recordings # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_recordings_with_http_info(async_req=True) - >>> result = thread.get() - - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(RecordingListResponse, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = [] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method get_recordings" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "200": "RecordingListResponse", - "404": "Error", - } - - return self.api_client.call_api( - "/recording", - "GET", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) diff --git a/jellyfish/_openapi_client/api/room/__init__.py b/jellyfish/_openapi_client/api/room/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jellyfish/_openapi_client/api/room/add_component.py b/jellyfish/_openapi_client/api/room/add_component.py new file mode 100644 index 0000000..86f492b --- /dev/null +++ b/jellyfish/_openapi_client/api/room/add_component.py @@ -0,0 +1,183 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.add_component_json_body import AddComponentJsonBody +from ...models.component_details_response import ComponentDetailsResponse +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + room_id: str, + *, + json_body: AddComponentJsonBody, +) -> Dict[str, Any]: + pass + + json_json_body = json_body.to_dict() + + return { + "method": "post", + "url": "/room/{room_id}/component".format( + room_id=room_id, + ), + "json": json_json_body, + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[ComponentDetailsResponse, Error]]: + if response.status_code == HTTPStatus.CREATED: + response_201 = ComponentDetailsResponse.from_dict(response.json()) + + return response_201 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[ComponentDetailsResponse, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddComponentJsonBody, +) -> Response[Union[ComponentDetailsResponse, Error]]: + """Creates the component and adds it to the room + + Args: + room_id (str): + json_body (AddComponentJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[ComponentDetailsResponse, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + json_body=json_body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddComponentJsonBody, +) -> Optional[Union[ComponentDetailsResponse, Error]]: + """Creates the component and adds it to the room + + Args: + room_id (str): + json_body (AddComponentJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[ComponentDetailsResponse, Error] + """ + + return sync_detailed( + room_id=room_id, + client=client, + json_body=json_body, + ).parsed + + +async def asyncio_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddComponentJsonBody, +) -> Response[Union[ComponentDetailsResponse, Error]]: + """Creates the component and adds it to the room + + Args: + room_id (str): + json_body (AddComponentJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[ComponentDetailsResponse, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + json_body=json_body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddComponentJsonBody, +) -> Optional[Union[ComponentDetailsResponse, Error]]: + """Creates the component and adds it to the room + + Args: + room_id (str): + json_body (AddComponentJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[ComponentDetailsResponse, Error] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + client=client, + json_body=json_body, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room/add_peer.py b/jellyfish/_openapi_client/api/room/add_peer.py new file mode 100644 index 0000000..4eb45e3 --- /dev/null +++ b/jellyfish/_openapi_client/api/room/add_peer.py @@ -0,0 +1,187 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.add_peer_json_body import AddPeerJsonBody +from ...models.error import Error +from ...models.peer_details_response import PeerDetailsResponse +from ...types import Response + + +def _get_kwargs( + room_id: str, + *, + json_body: AddPeerJsonBody, +) -> Dict[str, Any]: + pass + + json_json_body = json_body.to_dict() + + return { + "method": "post", + "url": "/room/{room_id}/peer".format( + room_id=room_id, + ), + "json": json_json_body, + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, PeerDetailsResponse]]: + if response.status_code == HTTPStatus.CREATED: + response_201 = PeerDetailsResponse.from_dict(response.json()) + + return response_201 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if response.status_code == HTTPStatus.SERVICE_UNAVAILABLE: + response_503 = Error.from_dict(response.json()) + + return response_503 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, PeerDetailsResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddPeerJsonBody, +) -> Response[Union[Error, PeerDetailsResponse]]: + """Create peer + + Args: + room_id (str): + json_body (AddPeerJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, PeerDetailsResponse]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + json_body=json_body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddPeerJsonBody, +) -> Optional[Union[Error, PeerDetailsResponse]]: + """Create peer + + Args: + room_id (str): + json_body (AddPeerJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, PeerDetailsResponse] + """ + + return sync_detailed( + room_id=room_id, + client=client, + json_body=json_body, + ).parsed + + +async def asyncio_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddPeerJsonBody, +) -> Response[Union[Error, PeerDetailsResponse]]: + """Create peer + + Args: + room_id (str): + json_body (AddPeerJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, PeerDetailsResponse]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + json_body=json_body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], + json_body: AddPeerJsonBody, +) -> Optional[Union[Error, PeerDetailsResponse]]: + """Create peer + + Args: + room_id (str): + json_body (AddPeerJsonBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, PeerDetailsResponse] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + client=client, + json_body=json_body, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room/create_room.py b/jellyfish/_openapi_client/api/room/create_room.py new file mode 100644 index 0000000..15da766 --- /dev/null +++ b/jellyfish/_openapi_client/api/room/create_room.py @@ -0,0 +1,164 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...models.room_config import RoomConfig +from ...models.room_create_details_response import RoomCreateDetailsResponse +from ...types import Response + + +def _get_kwargs( + *, + json_body: RoomConfig, +) -> Dict[str, Any]: + pass + + json_json_body = json_body.to_dict() + + return { + "method": "post", + "url": "/room", + "json": json_json_body, + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, RoomCreateDetailsResponse]]: + if response.status_code == HTTPStatus.CREATED: + response_201 = RoomCreateDetailsResponse.from_dict(response.json()) + + return response_201 + if response.status_code == HTTPStatus.BAD_REQUEST: + response_400 = Error.from_dict(response.json()) + + return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, RoomCreateDetailsResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + json_body: RoomConfig, +) -> Response[Union[Error, RoomCreateDetailsResponse]]: + """Creates a room + + Args: + json_body (RoomConfig): Room configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RoomCreateDetailsResponse]] + """ + + kwargs = _get_kwargs( + json_body=json_body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + json_body: RoomConfig, +) -> Optional[Union[Error, RoomCreateDetailsResponse]]: + """Creates a room + + Args: + json_body (RoomConfig): Room configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RoomCreateDetailsResponse] + """ + + return sync_detailed( + client=client, + json_body=json_body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + json_body: RoomConfig, +) -> Response[Union[Error, RoomCreateDetailsResponse]]: + """Creates a room + + Args: + json_body (RoomConfig): Room configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RoomCreateDetailsResponse]] + """ + + kwargs = _get_kwargs( + json_body=json_body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + json_body: RoomConfig, +) -> Optional[Union[Error, RoomCreateDetailsResponse]]: + """Creates a room + + Args: + json_body (RoomConfig): Room configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RoomCreateDetailsResponse] + """ + + return ( + await asyncio_detailed( + client=client, + json_body=json_body, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room/delete_component.py b/jellyfish/_openapi_client/api/room/delete_component.py new file mode 100644 index 0000000..766bd09 --- /dev/null +++ b/jellyfish/_openapi_client/api/room/delete_component.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + room_id: str, + id: str, +) -> Dict[str, Any]: + pass + + return { + "method": "delete", + "url": "/room/{room_id}/component/{id}".format( + room_id=room_id, + id=id, + ), + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Error]]: + if response.status_code == HTTPStatus.NO_CONTENT: + response_204 = cast(Any, None) + return response_204 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Delete the component from the room + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Delete the component from the room + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return sync_detailed( + room_id=room_id, + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Delete the component from the room + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Delete the component from the room + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + id=id, + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room/delete_peer.py b/jellyfish/_openapi_client/api/room/delete_peer.py new file mode 100644 index 0000000..b428950 --- /dev/null +++ b/jellyfish/_openapi_client/api/room/delete_peer.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + room_id: str, + id: str, +) -> Dict[str, Any]: + pass + + return { + "method": "delete", + "url": "/room/{room_id}/peer/{id}".format( + room_id=room_id, + id=id, + ), + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Error]]: + if response.status_code == HTTPStatus.NO_CONTENT: + response_204 = cast(Any, None) + return response_204 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Delete peer + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Delete peer + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return sync_detailed( + room_id=room_id, + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Delete peer + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Delete peer + + Args: + room_id (str): + id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + id=id, + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room/delete_room.py b/jellyfish/_openapi_client/api/room/delete_room.py new file mode 100644 index 0000000..e2554df --- /dev/null +++ b/jellyfish/_openapi_client/api/room/delete_room.py @@ -0,0 +1,159 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...types import Response + + +def _get_kwargs( + room_id: str, +) -> Dict[str, Any]: + pass + + return { + "method": "delete", + "url": "/room/{room_id}".format( + room_id=room_id, + ), + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Error]]: + if response.status_code == HTTPStatus.NO_CONTENT: + response_204 = cast(Any, None) + return response_204 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Error]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Delete the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Delete the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return sync_detailed( + room_id=room_id, + client=client, + ).parsed + + +async def asyncio_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, Error]]: + """Delete the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Error]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, Error]]: + """Delete the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Error] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room/get_all_rooms.py b/jellyfish/_openapi_client/api/room/get_all_rooms.py new file mode 100644 index 0000000..9664c25 --- /dev/null +++ b/jellyfish/_openapi_client/api/room/get_all_rooms.py @@ -0,0 +1,131 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...models.rooms_listing_response import RoomsListingResponse +from ...types import Response + + +def _get_kwargs() -> Dict[str, Any]: + pass + + return { + "method": "get", + "url": "/room", + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, RoomsListingResponse]]: + if response.status_code == HTTPStatus.OK: + response_200 = RoomsListingResponse.from_dict(response.json()) + + return response_200 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, RoomsListingResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, RoomsListingResponse]]: + """Show information about all rooms + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RoomsListingResponse]] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, RoomsListingResponse]]: + """Show information about all rooms + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RoomsListingResponse] + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, RoomsListingResponse]]: + """Show information about all rooms + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RoomsListingResponse]] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, RoomsListingResponse]]: + """Show information about all rooms + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RoomsListingResponse] + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room/get_room.py b/jellyfish/_openapi_client/api/room/get_room.py new file mode 100644 index 0000000..95ed166 --- /dev/null +++ b/jellyfish/_openapi_client/api/room/get_room.py @@ -0,0 +1,161 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error import Error +from ...models.room_details_response import RoomDetailsResponse +from ...types import Response + + +def _get_kwargs( + room_id: str, +) -> Dict[str, Any]: + pass + + return { + "method": "get", + "url": "/room/{room_id}".format( + room_id=room_id, + ), + } + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, RoomDetailsResponse]]: + if response.status_code == HTTPStatus.OK: + response_200 = RoomDetailsResponse.from_dict(response.json()) + + return response_200 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = Error.from_dict(response.json()) + + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = Error.from_dict(response.json()) + + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, RoomDetailsResponse]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, RoomDetailsResponse]]: + """Shows information about the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RoomDetailsResponse]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, RoomDetailsResponse]]: + """Shows information about the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RoomDetailsResponse] + """ + + return sync_detailed( + room_id=room_id, + client=client, + ).parsed + + +async def asyncio_detailed( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Error, RoomDetailsResponse]]: + """Shows information about the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, RoomDetailsResponse]] + """ + + kwargs = _get_kwargs( + room_id=room_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + room_id: str, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Error, RoomDetailsResponse]]: + """Shows information about the room + + Args: + room_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, RoomDetailsResponse] + """ + + return ( + await asyncio_detailed( + room_id=room_id, + client=client, + ) + ).parsed diff --git a/jellyfish/_openapi_client/api/room_api.py b/jellyfish/_openapi_client/api/room_api.py deleted file mode 100644 index d8ef113..0000000 --- a/jellyfish/_openapi_client/api/room_api.py +++ /dev/null @@ -1,1292 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import re # noqa: F401 -import io -import warnings - -from pydantic import validate_arguments, ValidationError -from typing_extensions import Annotated - -from pydantic import Field, StrictStr - -from typing import Optional - -from jellyfish._openapi_client.models.add_component_request import AddComponentRequest -from jellyfish._openapi_client.models.add_peer_request import AddPeerRequest -from jellyfish._openapi_client.models.component_details_response import ( - ComponentDetailsResponse, -) -from jellyfish._openapi_client.models.peer_details_response import PeerDetailsResponse -from jellyfish._openapi_client.models.room_config import RoomConfig -from jellyfish._openapi_client.models.room_create_details_response import ( - RoomCreateDetailsResponse, -) -from jellyfish._openapi_client.models.room_details_response import RoomDetailsResponse -from jellyfish._openapi_client.models.rooms_listing_response import RoomsListingResponse - -from jellyfish._openapi_client.api_client import ApiClient -from jellyfish._openapi_client.api_response import ApiResponse -from jellyfish._openapi_client.exceptions import ( # noqa: F401 - ApiTypeError, - ApiValueError, -) - - -class RoomApi(object): - """NOTE: This class is auto generated by OpenAPI Generator - Ref: https://openapi-generator.tech - - Do not edit the class manually. - """ - - def __init__(self, api_client=None): - if api_client is None: - api_client = ApiClient.get_default() - self.api_client = api_client - - @validate_arguments - def add_component( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - add_component_request: Annotated[ - Optional[AddComponentRequest], Field(description="Component config") - ] = None, - **kwargs - ) -> ComponentDetailsResponse: # noqa: E501 - """Creates the component and adds it to the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.add_component(room_id, add_component_request, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param add_component_request: Component config - :type add_component_request: AddComponentRequest - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: ComponentDetailsResponse - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the add_component_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.add_component_with_http_info( - room_id, add_component_request, **kwargs - ) # noqa: E501 - - @validate_arguments - def add_component_with_http_info( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - add_component_request: Annotated[ - Optional[AddComponentRequest], Field(description="Component config") - ] = None, - **kwargs - ) -> ApiResponse: # noqa: E501 - """Creates the component and adds it to the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.add_component_with_http_info(room_id, add_component_request, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param add_component_request: Component config - :type add_component_request: AddComponentRequest - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(ComponentDetailsResponse, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = ["room_id", "add_component_request"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method add_component" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - if _params["add_component_request"] is not None: - _body_params = _params["add_component_request"] - - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # set the HTTP header `Content-Type` - _content_types_list = _params.get( - "_content_type", - self.api_client.select_header_content_type(["application/json"]), - ) - if _content_types_list: - _header_params["Content-Type"] = _content_types_list - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "201": "ComponentDetailsResponse", - "400": "Error", - "401": "Error", - "404": "Error", - } - - return self.api_client.call_api( - "/room/{room_id}/component", - "POST", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def add_peer( - self, - room_id: Annotated[StrictStr, Field(..., description="Room id")], - add_peer_request: Annotated[ - Optional[AddPeerRequest], Field(description="Peer specification") - ] = None, - **kwargs - ) -> PeerDetailsResponse: # noqa: E501 - """Create peer # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.add_peer(room_id, add_peer_request, async_req=True) - >>> result = thread.get() - - :param room_id: Room id (required) - :type room_id: str - :param add_peer_request: Peer specification - :type add_peer_request: AddPeerRequest - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: PeerDetailsResponse - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the add_peer_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.add_peer_with_http_info( - room_id, add_peer_request, **kwargs - ) # noqa: E501 - - @validate_arguments - def add_peer_with_http_info( - self, - room_id: Annotated[StrictStr, Field(..., description="Room id")], - add_peer_request: Annotated[ - Optional[AddPeerRequest], Field(description="Peer specification") - ] = None, - **kwargs - ) -> ApiResponse: # noqa: E501 - """Create peer # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.add_peer_with_http_info(room_id, add_peer_request, async_req=True) - >>> result = thread.get() - - :param room_id: Room id (required) - :type room_id: str - :param add_peer_request: Peer specification - :type add_peer_request: AddPeerRequest - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(PeerDetailsResponse, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = ["room_id", "add_peer_request"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method add_peer" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - if _params["add_peer_request"] is not None: - _body_params = _params["add_peer_request"] - - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # set the HTTP header `Content-Type` - _content_types_list = _params.get( - "_content_type", - self.api_client.select_header_content_type(["application/json"]), - ) - if _content_types_list: - _header_params["Content-Type"] = _content_types_list - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "201": "PeerDetailsResponse", - "400": "Error", - "401": "Error", - "404": "Error", - "503": "Error", - } - - return self.api_client.call_api( - "/room/{room_id}/peer", - "POST", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def create_room( - self, - room_config: Annotated[ - Optional[RoomConfig], Field(description="Room configuration") - ] = None, - **kwargs - ) -> RoomCreateDetailsResponse: # noqa: E501 - """Creates a room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.create_room(room_config, async_req=True) - >>> result = thread.get() - - :param room_config: Room configuration - :type room_config: RoomConfig - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: RoomCreateDetailsResponse - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the create_room_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.create_room_with_http_info(room_config, **kwargs) # noqa: E501 - - @validate_arguments - def create_room_with_http_info( - self, - room_config: Annotated[ - Optional[RoomConfig], Field(description="Room configuration") - ] = None, - **kwargs - ) -> ApiResponse: # noqa: E501 - """Creates a room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.create_room_with_http_info(room_config, async_req=True) - >>> result = thread.get() - - :param room_config: Room configuration - :type room_config: RoomConfig - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(RoomCreateDetailsResponse, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = ["room_config"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method create_room" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - if _params["room_config"] is not None: - _body_params = _params["room_config"] - - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # set the HTTP header `Content-Type` - _content_types_list = _params.get( - "_content_type", - self.api_client.select_header_content_type(["application/json"]), - ) - if _content_types_list: - _header_params["Content-Type"] = _content_types_list - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "201": "RoomCreateDetailsResponse", - "400": "Error", - "401": "Error", - } - - return self.api_client.call_api( - "/room", - "POST", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def delete_component( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - id: Annotated[StrictStr, Field(..., description="Component ID")], - **kwargs - ) -> None: # noqa: E501 - """Delete the component from the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_component(room_id, id, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param id: Component ID (required) - :type id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the delete_component_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.delete_component_with_http_info(room_id, id, **kwargs) # noqa: E501 - - @validate_arguments - def delete_component_with_http_info( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - id: Annotated[StrictStr, Field(..., description="Component ID")], - **kwargs - ) -> ApiResponse: # noqa: E501 - """Delete the component from the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_component_with_http_info(room_id, id, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param id: Component ID (required) - :type id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - - _params = locals() - - _all_params = ["room_id", "id"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method delete_component" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - if _params["id"]: - _path_params["id"] = _params["id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = {} - - return self.api_client.call_api( - "/room/{room_id}/component/{id}", - "DELETE", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def delete_peer( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - id: Annotated[StrictStr, Field(..., description="Peer id")], - **kwargs - ) -> None: # noqa: E501 - """Delete peer # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_peer(room_id, id, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param id: Peer id (required) - :type id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the delete_peer_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.delete_peer_with_http_info(room_id, id, **kwargs) # noqa: E501 - - @validate_arguments - def delete_peer_with_http_info( - self, - room_id: Annotated[StrictStr, Field(..., description="Room ID")], - id: Annotated[StrictStr, Field(..., description="Peer id")], - **kwargs - ) -> ApiResponse: # noqa: E501 - """Delete peer # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_peer_with_http_info(room_id, id, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param id: Peer id (required) - :type id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - - _params = locals() - - _all_params = ["room_id", "id"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method delete_peer" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - if _params["id"]: - _path_params["id"] = _params["id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = {} - - return self.api_client.call_api( - "/room/{room_id}/peer/{id}", - "DELETE", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def delete_room( - self, room_id: Annotated[StrictStr, Field(..., description="Room id")], **kwargs - ) -> None: # noqa: E501 - """Delete the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_room(room_id, async_req=True) - >>> result = thread.get() - - :param room_id: Room id (required) - :type room_id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the delete_room_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.delete_room_with_http_info(room_id, **kwargs) # noqa: E501 - - @validate_arguments - def delete_room_with_http_info( - self, room_id: Annotated[StrictStr, Field(..., description="Room id")], **kwargs - ) -> ApiResponse: # noqa: E501 - """Delete the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.delete_room_with_http_info(room_id, async_req=True) - >>> result = thread.get() - - :param room_id: Room id (required) - :type room_id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: None - """ - - _params = locals() - - _all_params = ["room_id"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method delete_room" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = {} - - return self.api_client.call_api( - "/room/{room_id}", - "DELETE", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def get_all_rooms(self, **kwargs) -> RoomsListingResponse: # noqa: E501 - """Show information about all rooms # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_all_rooms(async_req=True) - >>> result = thread.get() - - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: RoomsListingResponse - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the get_all_rooms_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.get_all_rooms_with_http_info(**kwargs) # noqa: E501 - - @validate_arguments - def get_all_rooms_with_http_info(self, **kwargs) -> ApiResponse: # noqa: E501 - """Show information about all rooms # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_all_rooms_with_http_info(async_req=True) - >>> result = thread.get() - - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(RoomsListingResponse, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = [] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method get_all_rooms" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "200": "RoomsListingResponse", - "401": "Error", - } - - return self.api_client.call_api( - "/room", - "GET", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) - - @validate_arguments - def get_room( - self, room_id: Annotated[StrictStr, Field(..., description="Room ID")], **kwargs - ) -> RoomDetailsResponse: # noqa: E501 - """Shows information about the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_room(room_id, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: RoomDetailsResponse - """ - kwargs["_return_http_data_only"] = True - if "_preload_content" in kwargs: - raise ValueError( - "Error! Please call the get_room_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" - ) - return self.get_room_with_http_info(room_id, **kwargs) # noqa: E501 - - @validate_arguments - def get_room_with_http_info( - self, room_id: Annotated[StrictStr, Field(..., description="Room ID")], **kwargs - ) -> ApiResponse: # noqa: E501 - """Shows information about the room # noqa: E501 - - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True - - >>> thread = api.get_room_with_http_info(room_id, async_req=True) - >>> result = thread.get() - - :param room_id: Room ID (required) - :type room_id: str - :param async_req: Whether to execute the request asynchronously. - :type async_req: bool, optional - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :type _preload_content: bool, optional - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :type _return_http_data_only: bool, optional - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_auth: dict, optional - :type _content_type: string, optional: force content-type for the request - :return: Returns the result object. - If the method is called asynchronously, - returns the request thread. - :rtype: tuple(RoomDetailsResponse, status_code(int), headers(HTTPHeaderDict)) - """ - - _params = locals() - - _all_params = ["room_id"] - _all_params.extend( - [ - "async_req", - "_return_http_data_only", - "_preload_content", - "_request_timeout", - "_request_auth", - "_content_type", - "_headers", - ] - ) - - # validate the arguments - for _key, _val in _params["kwargs"].items(): - if _key not in _all_params: - raise ApiTypeError( - "Got an unexpected keyword argument '%s'" - " to method get_room" % _key - ) - _params[_key] = _val - del _params["kwargs"] - - _collection_formats = {} - - # process the path parameters - _path_params = {} - if _params["room_id"]: - _path_params["room_id"] = _params["room_id"] - - # process the query parameters - _query_params = [] - # process the header parameters - _header_params = dict(_params.get("_headers", {})) - # process the form parameters - _form_params = [] - _files = {} - # process the body parameter - _body_params = None - # set the HTTP header `Accept` - _header_params["Accept"] = self.api_client.select_header_accept( - ["application/json"] - ) # noqa: E501 - - # authentication setting - _auth_settings = ["authorization"] # noqa: E501 - - _response_types_map = { - "200": "RoomDetailsResponse", - "401": "Error", - "404": "Error", - } - - return self.api_client.call_api( - "/room/{room_id}", - "GET", - _path_params, - _query_params, - _header_params, - body=_body_params, - post_params=_form_params, - files=_files, - response_types_map=_response_types_map, - auth_settings=_auth_settings, - async_req=_params.get("async_req"), - _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501 - _preload_content=_params.get("_preload_content", True), - _request_timeout=_params.get("_request_timeout"), - collection_formats=_collection_formats, - _request_auth=_params.get("_request_auth"), - ) diff --git a/jellyfish/_openapi_client/api_client.py b/jellyfish/_openapi_client/api_client.py deleted file mode 100644 index 029df4d..0000000 --- a/jellyfish/_openapi_client/api_client.py +++ /dev/null @@ -1,835 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import atexit -import datetime -from dateutil.parser import parse -import json -import mimetypes -from multiprocessing.pool import ThreadPool -import os -import re -import tempfile - -from urllib.parse import quote - -from jellyfish._openapi_client.configuration import Configuration -from jellyfish._openapi_client.api_response import ApiResponse -import jellyfish._openapi_client.models -from jellyfish._openapi_client import rest -from jellyfish._openapi_client.exceptions import ApiValueError, ApiException - - -class ApiClient(object): - """Generic API client for OpenAPI client library builds. - - OpenAPI generic API client. This client handles the client- - server communication, and is invariant across implementations. Specifics of - the methods and models for each application are generated from the OpenAPI - templates. - - :param configuration: .Configuration object for this client - :param header_name: a header to pass when making calls to the API. - :param header_value: a header value to pass when making calls to - the API. - :param cookie: a cookie to include in the header when making calls - to the API - :param pool_threads: The number of threads to use for async requests - to the API. More threads means more concurrent API requests. - """ - - PRIMITIVE_TYPES = (float, bool, bytes, str, int) - NATIVE_TYPES_MAPPING = { - "int": int, - "long": int, # TODO remove as only py3 is supported? - "float": float, - "str": str, - "bool": bool, - "date": datetime.date, - "datetime": datetime.datetime, - "object": object, - } - _pool = None - - def __init__( - self, - configuration=None, - header_name=None, - header_value=None, - cookie=None, - pool_threads=1, - ): - # use default configuration if none is provided - if configuration is None: - configuration = Configuration.get_default() - self.configuration = configuration - self.pool_threads = pool_threads - - self.rest_client = rest.RESTClientObject(configuration) - self.default_headers = {} - if header_name is not None: - self.default_headers[header_name] = header_value - self.cookie = cookie - # Set default User-Agent. - self.user_agent = "OpenAPI-Generator/1.0.0/python" - self.client_side_validation = configuration.client_side_validation - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.close() - - def close(self): - if self._pool: - self._pool.close() - self._pool.join() - self._pool = None - if hasattr(atexit, "unregister"): - atexit.unregister(self.close) - - @property - def pool(self): - """Create thread pool on first request - avoids instantiating unused threadpool for blocking clients. - """ - if self._pool is None: - atexit.register(self.close) - self._pool = ThreadPool(self.pool_threads) - return self._pool - - @property - def user_agent(self): - """User agent for this API client""" - return self.default_headers["User-Agent"] - - @user_agent.setter - def user_agent(self, value): - self.default_headers["User-Agent"] = value - - def set_default_header(self, header_name, header_value): - self.default_headers[header_name] = header_value - - _default = None - - @classmethod - def get_default(cls): - """Return new instance of ApiClient. - - This method returns newly created, based on default constructor, - object of ApiClient class or returns a copy of default - ApiClient. - - :return: The ApiClient object. - """ - if cls._default is None: - cls._default = ApiClient() - return cls._default - - @classmethod - def set_default(cls, default): - """Set default instance of ApiClient. - - It stores default ApiClient. - - :param default: object of ApiClient. - """ - cls._default = default - - def __call_api( - self, - resource_path, - method, - path_params=None, - query_params=None, - header_params=None, - body=None, - post_params=None, - files=None, - response_types_map=None, - auth_settings=None, - _return_http_data_only=None, - collection_formats=None, - _preload_content=True, - _request_timeout=None, - _host=None, - _request_auth=None, - ): - config = self.configuration - - # header parameters - header_params = header_params or {} - header_params.update(self.default_headers) - if self.cookie: - header_params["Cookie"] = self.cookie - if header_params: - header_params = self.sanitize_for_serialization(header_params) - header_params = dict( - self.parameters_to_tuples(header_params, collection_formats) - ) - - # path parameters - if path_params: - path_params = self.sanitize_for_serialization(path_params) - path_params = self.parameters_to_tuples(path_params, collection_formats) - for k, v in path_params: - # specified safe chars, encode everything - resource_path = resource_path.replace( - "{%s}" % k, quote(str(v), safe=config.safe_chars_for_path_param) - ) - - # post parameters - if post_params or files: - post_params = post_params if post_params else [] - post_params = self.sanitize_for_serialization(post_params) - post_params = self.parameters_to_tuples(post_params, collection_formats) - post_params.extend(self.files_parameters(files)) - - # auth setting - self.update_params_for_auth( - header_params, - query_params, - auth_settings, - resource_path, - method, - body, - request_auth=_request_auth, - ) - - # body - if body: - body = self.sanitize_for_serialization(body) - - # request url - if _host is None: - url = self.configuration.host + resource_path - else: - # use server/host defined in path or operation instead - url = _host + resource_path - - # query parameters - if query_params: - query_params = self.sanitize_for_serialization(query_params) - url_query = self.parameters_to_url_query(query_params, collection_formats) - url += "?" + url_query - - try: - # perform request and return response - response_data = self.request( - method, - url, - query_params=query_params, - headers=header_params, - post_params=post_params, - body=body, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - ) - except ApiException as e: - if e.body: - e.body = e.body.decode("utf-8") - raise e - - self.last_response = response_data - - return_data = None # assuming derialization is not needed - # data needs deserialization or returns HTTP data (deserialized) only - if _preload_content or _return_http_data_only: - response_type = response_types_map.get(str(response_data.status), None) - - if response_type == "bytearray": - response_data.data = response_data.data - else: - match = None - content_type = response_data.getheader("content-type") - if content_type is not None: - match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) - encoding = match.group(1) if match else "utf-8" - response_data.data = response_data.data.decode(encoding) - - # deserialize response data - if response_type == "bytearray": - return_data = response_data.data - elif response_type: - return_data = self.deserialize(response_data, response_type) - else: - return_data = None - - if _return_http_data_only: - return return_data - else: - return ApiResponse( - status_code=response_data.status, - data=return_data, - headers=response_data.getheaders(), - raw_data=response_data.data, - ) - - def sanitize_for_serialization(self, obj): - """Builds a JSON POST object. - - If obj is None, return None. - If obj is str, int, long, float, bool, return directly. - If obj is datetime.datetime, datetime.date - convert to string in iso8601 format. - If obj is list, sanitize each element in the list. - If obj is dict, return the dict. - If obj is OpenAPI model, return the properties dict. - - :param obj: The data to serialize. - :return: The serialized form of data. - """ - if obj is None: - return None - elif isinstance(obj, self.PRIMITIVE_TYPES): - return obj - elif isinstance(obj, list): - return [self.sanitize_for_serialization(sub_obj) for sub_obj in obj] - elif isinstance(obj, tuple): - return tuple(self.sanitize_for_serialization(sub_obj) for sub_obj in obj) - elif isinstance(obj, (datetime.datetime, datetime.date)): - return obj.isoformat() - - if isinstance(obj, dict): - obj_dict = obj - else: - # Convert model obj to dict except - # attributes `openapi_types`, `attribute_map` - # and attributes which value is not None. - # Convert attribute name to json key in - # model definition for request. - obj_dict = obj.to_dict() - - return { - key: self.sanitize_for_serialization(val) for key, val in obj_dict.items() - } - - def deserialize(self, response, response_type): - """Deserializes response into an object. - - :param response: RESTResponse object to be deserialized. - :param response_type: class literal for - deserialized object, or string of class name. - - :return: deserialized object. - """ - # handle file downloading - # save response body into a tmp file and return the instance - if response_type == "file": - return self.__deserialize_file(response) - - # fetch data from response object - try: - data = json.loads(response.data) - except ValueError: - data = response.data - - return self.__deserialize(data, response_type) - - def __deserialize(self, data, klass): - """Deserializes dict, list, str into an object. - - :param data: dict, list or str. - :param klass: class literal, or string of class name. - - :return: object. - """ - if data is None: - return None - - if type(klass) == str: - if klass.startswith("List["): - sub_kls = re.match(r"List\[(.*)]", klass).group(1) - return [self.__deserialize(sub_data, sub_kls) for sub_data in data] - - if klass.startswith("Dict["): - sub_kls = re.match(r"Dict\[([^,]*), (.*)]", klass).group(2) - return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} - - # convert str to class - if klass in self.NATIVE_TYPES_MAPPING: - klass = self.NATIVE_TYPES_MAPPING[klass] - else: - klass = getattr(jellyfish._openapi_client.models, klass) - - if klass in self.PRIMITIVE_TYPES: - return self.__deserialize_primitive(data, klass) - elif klass == object: - return self.__deserialize_object(data) - elif klass == datetime.date: - return self.__deserialize_date(data) - elif klass == datetime.datetime: - return self.__deserialize_datetime(data) - else: - return self.__deserialize_model(data, klass) - - def call_api( - self, - resource_path, - method, - path_params=None, - query_params=None, - header_params=None, - body=None, - post_params=None, - files=None, - response_types_map=None, - auth_settings=None, - async_req=None, - _return_http_data_only=None, - collection_formats=None, - _preload_content=True, - _request_timeout=None, - _host=None, - _request_auth=None, - ): - """Makes the HTTP request (synchronous) and returns deserialized data. - - To make an async_req request, set the async_req parameter. - - :param resource_path: Path to method endpoint. - :param method: Method to call. - :param path_params: Path parameters in the url. - :param query_params: Query parameters in the url. - :param header_params: Header parameters to be - placed in the request header. - :param body: Request body. - :param post_params dict: Request post form parameters, - for `application/x-www-form-urlencoded`, `multipart/form-data`. - :param auth_settings list: Auth Settings names for the request. - :param response: Response data type. - :param files dict: key -> filename, value -> filepath, - for `multipart/form-data`. - :param async_req bool: execute request asynchronously - :param _return_http_data_only: response data instead of ApiResponse - object with status code, headers, etc - :param _preload_content: if False, the ApiResponse.data will - be set to none and raw_data will store the - HTTP response body without reading/decoding. - Default is True. - :param collection_formats: dict of collection formats for path, query, - header, and post parameters. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :param _request_auth: set to override the auth_settings for an a single - request; this effectively ignores the authentication - in the spec for a single request. - :type _request_token: dict, optional - :return: - If async_req parameter is True, - the request will be called asynchronously. - The method will return the request thread. - If parameter async_req is False or missing, - then the method will return the response directly. - """ - if not async_req: - return self.__call_api( - resource_path, - method, - path_params, - query_params, - header_params, - body, - post_params, - files, - response_types_map, - auth_settings, - _return_http_data_only, - collection_formats, - _preload_content, - _request_timeout, - _host, - _request_auth, - ) - - return self.pool.apply_async( - self.__call_api, - ( - resource_path, - method, - path_params, - query_params, - header_params, - body, - post_params, - files, - response_types_map, - auth_settings, - _return_http_data_only, - collection_formats, - _preload_content, - _request_timeout, - _host, - _request_auth, - ), - ) - - def request( - self, - method, - url, - query_params=None, - headers=None, - post_params=None, - body=None, - _preload_content=True, - _request_timeout=None, - ): - """Makes the HTTP request using RESTClient.""" - if method == "GET": - return self.rest_client.get_request( - url, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - headers=headers, - ) - elif method == "HEAD": - return self.rest_client.head_request( - url, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - headers=headers, - ) - elif method == "OPTIONS": - return self.rest_client.options_request( - url, - query_params=query_params, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - ) - elif method == "POST": - return self.rest_client.post_request( - url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - elif method == "PUT": - return self.rest_client.put_request( - url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - elif method == "PATCH": - return self.rest_client.patch_request( - url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - elif method == "DELETE": - return self.rest_client.delete_request( - url, - query_params=query_params, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - else: - raise ApiValueError( - "http method must be `GET`, `HEAD`, `OPTIONS`," - " `POST`, `PATCH`, `PUT` or `DELETE`." - ) - - def parameters_to_tuples(self, params, collection_formats): - """Get parameters as list of tuples, formatting collections. - - :param params: Parameters as dict or list of two-tuples - :param dict collection_formats: Parameter collection formats - :return: Parameters as list of tuples, collections formatted - """ - new_params = [] - if collection_formats is None: - collection_formats = {} - for k, v in ( - params.items() if isinstance(params, dict) else params - ): # noqa: E501 - if k in collection_formats: - collection_format = collection_formats[k] - if collection_format == "multi": - new_params.extend((k, value) for value in v) - else: - if collection_format == "ssv": - delimiter = " " - elif collection_format == "tsv": - delimiter = "\t" - elif collection_format == "pipes": - delimiter = "|" - else: # csv is the default - delimiter = "," - new_params.append((k, delimiter.join(str(value) for value in v))) - else: - new_params.append((k, v)) - return new_params - - def parameters_to_url_query(self, params, collection_formats): - """Get parameters as list of tuples, formatting collections. - - :param params: Parameters as dict or list of two-tuples - :param dict collection_formats: Parameter collection formats - :return: URL query string (e.g. a=Hello%20World&b=123) - """ - new_params = [] - if collection_formats is None: - collection_formats = {} - for k, v in ( - params.items() if isinstance(params, dict) else params - ): # noqa: E501 - if isinstance(v, (int, float)): - v = str(v) - if isinstance(v, bool): - v = str(v).lower() - if isinstance(v, dict): - v = json.dumps(v) - - if k in collection_formats: - collection_format = collection_formats[k] - if collection_format == "multi": - new_params.extend((k, value) for value in v) - else: - if collection_format == "ssv": - delimiter = " " - elif collection_format == "tsv": - delimiter = "\t" - elif collection_format == "pipes": - delimiter = "|" - else: # csv is the default - delimiter = "," - new_params.append( - (k, delimiter.join(quote(str(value)) for value in v)) - ) - else: - new_params.append((k, quote(str(v)))) - - return "&".join(["=".join(item) for item in new_params]) - - def files_parameters(self, files=None): - """Builds form parameters. - - :param files: File parameters. - :return: Form parameters with files. - """ - params = [] - - if files: - for k, v in files.items(): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, "rb") as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = ( - mimetypes.guess_type(filename)[0] - or "application/octet-stream" - ) - params.append(tuple([k, tuple([filename, filedata, mimetype])])) - - return params - - def select_header_accept(self, accepts): - """Returns `Accept` based on an array of accepts provided. - - :param accepts: List of headers. - :return: Accept (e.g. application/json). - """ - if not accepts: - return - - for accept in accepts: - if re.search("json", accept, re.IGNORECASE): - return accept - - return accepts[0] - - def select_header_content_type(self, content_types): - """Returns `Content-Type` based on an array of content_types provided. - - :param content_types: List of content-types. - :return: Content-Type (e.g. application/json). - """ - if not content_types: - return None - - for content_type in content_types: - if re.search("json", content_type, re.IGNORECASE): - return content_type - - return content_types[0] - - def update_params_for_auth( - self, - headers, - queries, - auth_settings, - resource_path, - method, - body, - request_auth=None, - ): - """Updates header and query params based on authentication setting. - - :param headers: Header parameters dict to be updated. - :param queries: Query parameters tuple list to be updated. - :param auth_settings: Authentication setting identifiers list. - :resource_path: A string representation of the HTTP request resource path. - :method: A string representation of the HTTP request method. - :body: A object representing the body of the HTTP request. - The object type is the return value of sanitize_for_serialization(). - :param request_auth: if set, the provided settings will - override the token in the configuration. - """ - if not auth_settings: - return - - if request_auth: - self._apply_auth_params( - headers, queries, resource_path, method, body, request_auth - ) - return - - for auth in auth_settings: - auth_setting = self.configuration.auth_settings().get(auth) - if auth_setting: - self._apply_auth_params( - headers, queries, resource_path, method, body, auth_setting - ) - - def _apply_auth_params( - self, headers, queries, resource_path, method, body, auth_setting - ): - """Updates the request parameters based on a single auth_setting - - :param headers: Header parameters dict to be updated. - :param queries: Query parameters tuple list to be updated. - :resource_path: A string representation of the HTTP request resource path. - :method: A string representation of the HTTP request method. - :body: A object representing the body of the HTTP request. - The object type is the return value of sanitize_for_serialization(). - :param auth_setting: auth settings for the endpoint - """ - if auth_setting["in"] == "cookie": - headers["Cookie"] = auth_setting["value"] - elif auth_setting["in"] == "header": - if auth_setting["type"] != "http-signature": - headers[auth_setting["key"]] = auth_setting["value"] - elif auth_setting["in"] == "query": - queries.append((auth_setting["key"], auth_setting["value"])) - else: - raise ApiValueError("Authentication token must be in `query` or `header`") - - def __deserialize_file(self, response): - """Deserializes body to file - - Saves response body into a file in a temporary folder, - using the filename from the `Content-Disposition` header if provided. - - :param response: RESTResponse. - :return: file path. - """ - fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path) - os.close(fd) - os.remove(path) - - content_disposition = response.getheader("Content-Disposition") - if content_disposition: - filename = re.search( - r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition - ).group(1) - path = os.path.join(os.path.dirname(path), filename) - - with open(path, "wb") as f: - f.write(response.data) - - return path - - def __deserialize_primitive(self, data, klass): - """Deserializes string to primitive type. - - :param data: str. - :param klass: class literal. - - :return: int, long, float, str, bool. - """ - try: - return klass(data) - except UnicodeEncodeError: - return str(data) - except TypeError: - return data - - def __deserialize_object(self, value): - """Return an original value. - - :return: object. - """ - return value - - def __deserialize_date(self, string): - """Deserializes string to date. - - :param string: str. - :return: date. - """ - try: - return parse(string).date() - except ImportError: - return string - except ValueError: - raise rest.ApiException( - status=0, reason="Failed to parse `{0}` as date object".format(string) - ) - - def __deserialize_datetime(self, string): - """Deserializes string to datetime. - - The string should be in iso8601 datetime format. - - :param string: str. - :return: datetime. - """ - try: - return parse(string) - except ImportError: - return string - except ValueError: - raise rest.ApiException( - status=0, - reason=("Failed to parse `{0}` as datetime object".format(string)), - ) - - def __deserialize_model(self, data, klass): - """Deserializes list or dict to model. - - :param data: dict, list. - :param klass: class literal. - :return: model object. - """ - - return klass.from_dict(data) diff --git a/jellyfish/_openapi_client/api_response.py b/jellyfish/_openapi_client/api_response.py deleted file mode 100644 index 0af0a2d..0000000 --- a/jellyfish/_openapi_client/api_response.py +++ /dev/null @@ -1,26 +0,0 @@ -"""API response object.""" - -from __future__ import annotations -from typing import Any, Dict, Optional -from pydantic import Field, StrictInt, StrictStr - - -class ApiResponse: - """ - API response object - """ - - status_code: Optional[StrictInt] = Field(None, description="HTTP status code") - headers: Optional[Dict[StrictStr, StrictStr]] = Field( - None, description="HTTP headers" - ) - data: Optional[Any] = Field( - None, description="Deserialized data given the data type" - ) - raw_data: Optional[Any] = Field(None, description="Raw data (HTTP response body)") - - def __init__(self, status_code=None, headers=None, data=None, raw_data=None): - self.status_code = status_code - self.headers = headers - self.data = data - self.raw_data = raw_data diff --git a/jellyfish/_openapi_client/client.py b/jellyfish/_openapi_client/client.py new file mode 100644 index 0000000..0a07559 --- /dev/null +++ b/jellyfish/_openapi_client/client.py @@ -0,0 +1,274 @@ +import ssl +from typing import Any, Dict, Optional, Union + +import httpx +from attrs import define, evolve, field + + +@define +class Client: + """A class for keeping track of data related to the API + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str + _cookies: Dict[str, str] = field(factory=dict, kw_only=True) + _headers: Dict[str, str] = field(factory=dict, kw_only=True) + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True) + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True) + _follow_redirects: bool = field(default=False, kw_only=True) + _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True) + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + def with_headers(self, headers: Dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: Dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + token: The token to use for authentication + prefix: The prefix to use for the Authorization header + auth_header_name: The name of the Authorization header + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str + _cookies: Dict[str, str] = field(factory=dict, kw_only=True) + _headers: Dict[str, str] = field(factory=dict, kw_only=True) + _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True) + _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True) + _follow_redirects: bool = field(default=False, kw_only=True) + _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True) + _client: Optional[httpx.Client] = field(default=None, init=False) + _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: Dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: Dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout (in seconds)""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = ( + f"{self.prefix} {self.token}" if self.prefix else self.token + ) + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client( + self, async_client: httpx.AsyncClient + ) -> "AuthenticatedClient": + """Manually the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = ( + f"{self.prefix} {self.token}" if self.prefix else self.token + ) + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/jellyfish/_openapi_client/configuration.py b/jellyfish/_openapi_client/configuration.py deleted file mode 100644 index 0d45d5c..0000000 --- a/jellyfish/_openapi_client/configuration.py +++ /dev/null @@ -1,458 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import copy -import logging -import multiprocessing -import sys -import urllib3 - -import http.client as httplib -from jellyfish._openapi_client.exceptions import ApiValueError - -JSON_SCHEMA_VALIDATION_KEYWORDS = { - "multipleOf", - "maximum", - "exclusiveMaximum", - "minimum", - "exclusiveMinimum", - "maxLength", - "minLength", - "pattern", - "maxItems", - "minItems", -} - - -class Configuration(object): - """This class contains various settings of the API client. - - :param host: Base url. - :param api_key: Dict to store API key(s). - Each entry in the dict specifies an API key. - The dict key is the name of the security scheme in the OAS specification. - The dict value is the API key secret. - :param api_key_prefix: Dict to store API prefix (e.g. Bearer). - The dict key is the name of the security scheme in the OAS specification. - The dict value is an API key prefix when generating the auth data. - :param username: Username for HTTP basic authentication. - :param password: Password for HTTP basic authentication. - :param access_token: Access token. - :param server_index: Index to servers configuration. - :param server_variables: Mapping with string values to replace variables in - templated server configuration. The validation of enums is performed for - variables with defined enum values before. - :param server_operation_index: Mapping from operation ID to an index to server - configuration. - :param server_operation_variables: Mapping from operation ID to a mapping with - string values to replace variables in templated server configuration. - The validation of enums is performed for variables with defined enum values before. - :param ssl_ca_cert: str - the path to a file of concatenated CA certificates - in PEM format. - - :Example: - """ - - _default = None - - def __init__( - self, - host=None, - api_key=None, - api_key_prefix=None, - username=None, - password=None, - access_token=None, - server_index=None, - server_variables=None, - server_operation_index=None, - server_operation_variables=None, - ssl_ca_cert=None, - ): - """Constructor""" - self._base_path = "http://localhost" if host is None else host - """Default Base url - """ - self.server_index = 0 if server_index is None and host is None else server_index - self.server_operation_index = server_operation_index or {} - """Default server index - """ - self.server_variables = server_variables or {} - self.server_operation_variables = server_operation_variables or {} - """Default server variables - """ - self.temp_folder_path = None - """Temp file folder for downloading files - """ - # Authentication Settings - self.api_key = {} - if api_key: - self.api_key = api_key - """dict to store API key(s) - """ - self.api_key_prefix = {} - if api_key_prefix: - self.api_key_prefix = api_key_prefix - """dict to store API prefix (e.g. Bearer) - """ - self.refresh_api_key_hook = None - """function hook to refresh API key if expired - """ - self.username = username - """Username for HTTP basic authentication - """ - self.password = password - """Password for HTTP basic authentication - """ - self.access_token = access_token - """Access token - """ - self.logger = {} - """Logging Settings - """ - self.logger["package_logger"] = logging.getLogger("jellyfish._openapi_client") - self.logger["urllib3_logger"] = logging.getLogger("urllib3") - self.logger_format = "%(asctime)s %(levelname)s %(message)s" - """Log format - """ - self.logger_stream_handler = None - """Log stream handler - """ - self.logger_file_handler = None - """Log file handler - """ - self.logger_file = None - """Debug file location - """ - self.debug = False - """Debug switch - """ - - self.verify_ssl = True - """SSL/TLS verification - Set this to false to skip verifying SSL certificate when calling API - from https server. - """ - self.ssl_ca_cert = ssl_ca_cert - """Set this to customize the certificate file to verify the peer. - """ - self.cert_file = None - """client certificate file - """ - self.key_file = None - """client key file - """ - self.assert_hostname = None - """Set this to True/False to enable/disable SSL hostname verification. - """ - self.tls_server_name = None - """SSL/TLS Server Name Indication (SNI) - Set this to the SNI value expected by the server. - """ - - self.connection_pool_maxsize = multiprocessing.cpu_count() * 5 - """urllib3 connection pool's maximum number of connections saved - per pool. urllib3 uses 1 connection as default value, but this is - not the best value when you are making a lot of possibly parallel - requests to the same host, which is often the case here. - cpu_count * 5 is used as default value to increase performance. - """ - - self.proxy = None - """Proxy URL - """ - self.proxy_headers = None - """Proxy headers - """ - self.safe_chars_for_path_param = "" - """Safe chars for path_param - """ - self.retries = None - """Adding retries to override urllib3 default value 3 - """ - # Enable client side validation - self.client_side_validation = True - - self.socket_options = None - """Options to pass down to the underlying urllib3 socket - """ - - self.datetime_format = "%Y-%m-%dT%H:%M:%S.%f%z" - """datetime format - """ - - self.date_format = "%Y-%m-%d" - """date format - """ - - def __deepcopy__(self, memo): - cls = self.__class__ - result = cls.__new__(cls) - memo[id(self)] = result - for k, v in self.__dict__.items(): - if k not in ("logger", "logger_file_handler"): - setattr(result, k, copy.deepcopy(v, memo)) - # shallow copy of loggers - result.logger = copy.copy(self.logger) - # use setters to configure loggers - result.logger_file = self.logger_file - result.debug = self.debug - return result - - def __setattr__(self, name, value): - object.__setattr__(self, name, value) - - @classmethod - def set_default(cls, default): - """Set default instance of configuration. - - It stores default configuration, which can be - returned by get_default_copy method. - - :param default: object of Configuration - """ - cls._default = default - - @classmethod - def get_default_copy(cls): - """Deprecated. Please use `get_default` instead. - - Deprecated. Please use `get_default` instead. - - :return: The configuration object. - """ - return cls.get_default() - - @classmethod - def get_default(cls): - """Return the default configuration. - - This method returns newly created, based on default constructor, - object of Configuration class or returns a copy of default - configuration. - - :return: The configuration object. - """ - if cls._default is None: - cls._default = Configuration() - return cls._default - - @property - def logger_file(self): - """The logger file. - - If the logger_file is None, then add stream handler and remove file - handler. Otherwise, add file handler and remove stream handler. - - :param value: The logger_file path. - :type: str - """ - return self.__logger_file - - @logger_file.setter - def logger_file(self, value): - """The logger file. - - If the logger_file is None, then add stream handler and remove file - handler. Otherwise, add file handler and remove stream handler. - - :param value: The logger_file path. - :type: str - """ - self.__logger_file = value - if self.__logger_file: - # If set logging file, - # then add file handler and remove stream handler. - self.logger_file_handler = logging.FileHandler(self.__logger_file) - self.logger_file_handler.setFormatter(self.logger_formatter) - for _, logger in self.logger.items(): - logger.addHandler(self.logger_file_handler) - - @property - def debug(self): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - return self.__debug - - @debug.setter - def debug(self, value): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - self.__debug = value - if self.__debug: - # if debug status is True, turn on debug logging - for _, logger in self.logger.items(): - logger.setLevel(logging.DEBUG) - # turn on httplib debug - httplib.HTTPConnection.debuglevel = 1 - else: - # if debug status is False, turn off debug logging, - # setting log level to default `logging.WARNING` - for _, logger in self.logger.items(): - logger.setLevel(logging.WARNING) - # turn off httplib debug - httplib.HTTPConnection.debuglevel = 0 - - @property - def logger_format(self): - """The logger format. - - The logger_formatter will be updated when sets logger_format. - - :param value: The format string. - :type: str - """ - return self.__logger_format - - @logger_format.setter - def logger_format(self, value): - """The logger format. - - The logger_formatter will be updated when sets logger_format. - - :param value: The format string. - :type: str - """ - self.__logger_format = value - self.logger_formatter = logging.Formatter(self.__logger_format) - - def get_api_key_with_prefix(self, identifier, alias=None): - """Gets API key (with prefix if set). - - :param identifier: The identifier of apiKey. - :param alias: The alternative identifier of apiKey. - :return: The token for api key authentication. - """ - if self.refresh_api_key_hook is not None: - self.refresh_api_key_hook(self) - key = self.api_key.get( - identifier, self.api_key.get(alias) if alias is not None else None - ) - if key: - prefix = self.api_key_prefix.get(identifier) - if prefix: - return "%s %s" % (prefix, key) - else: - return key - - def get_basic_auth_token(self): - """Gets HTTP basic authentication header (string). - - :return: The token for basic HTTP authentication. - """ - username = "" - if self.username is not None: - username = self.username - password = "" - if self.password is not None: - password = self.password - return urllib3.util.make_headers(basic_auth=username + ":" + password).get( - "authorization" - ) - - def auth_settings(self): - """Gets Auth Settings dict for api client. - - :return: The Auth Settings information dict. - """ - auth = {} - if self.access_token is not None: - auth["authorization"] = { - "type": "bearer", - "in": "header", - "key": "Authorization", - "value": "Bearer " + self.access_token, - } - return auth - - def to_debug_report(self): - """Gets the essential information for debugging. - - :return: The report for debugging. - """ - return ( - "Python SDK Debug Report:\n" - "OS: {env}\n" - "Python Version: {pyversion}\n" - "Version of the API: 0.2.0\n" - "SDK Package Version: 1.0.0".format(env=sys.platform, pyversion=sys.version) - ) - - def get_host_settings(self): - """Gets an array of host settings - - :return: An array of host settings - """ - return [ - { - "url": "", - "description": "No description provided", - } - ] - - def get_host_from_settings(self, index, variables=None, servers=None): - """Gets host URL based on the index and variables - :param index: array index of the host settings - :param variables: hash of variable and the corresponding value - :param servers: an array of host settings or None - :return: URL based on host settings - """ - if index is None: - return self._base_path - - variables = {} if variables is None else variables - servers = self.get_host_settings() if servers is None else servers - - try: - server = servers[index] - except IndexError: - raise ValueError( - "Invalid index {0} when selecting the host settings. " - "Must be less than {1}".format(index, len(servers)) - ) - - url = server["url"] - - # go through variables and replace placeholders - for variable_name, variable in server.get("variables", {}).items(): - used_value = variables.get(variable_name, variable["default_value"]) - - if "enum_values" in variable and used_value not in variable["enum_values"]: - raise ValueError( - "The variable `{0}` in the host URL has invalid value " - "{1}. Must be {2}.".format( - variable_name, variables[variable_name], variable["enum_values"] - ) - ) - - url = url.replace("{" + variable_name + "}", used_value) - - return url - - @property - def host(self): - """Return generated host.""" - return self.get_host_from_settings( - self.server_index, variables=self.server_variables - ) - - @host.setter - def host(self, value): - """Fix base path.""" - self._base_path = value - self.server_index = None diff --git a/jellyfish/_openapi_client/errors.py b/jellyfish/_openapi_client/errors.py new file mode 100644 index 0000000..426f8a2 --- /dev/null +++ b/jellyfish/_openapi_client/errors.py @@ -0,0 +1,14 @@ +""" Contains shared errors types that can be raised from API functions """ + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__(f"Unexpected status code: {status_code}") + + +__all__ = ["UnexpectedStatus"] diff --git a/jellyfish/_openapi_client/exceptions.py b/jellyfish/_openapi_client/exceptions.py deleted file mode 100644 index 3a6c92c..0000000 --- a/jellyfish/_openapi_client/exceptions.py +++ /dev/null @@ -1,157 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -class OpenApiException(Exception): - """The base exception class for all OpenAPIExceptions""" - - -class ApiTypeError(OpenApiException, TypeError): - def __init__(self, msg, path_to_item=None, valid_classes=None, key_type=None): - """Raises an exception for TypeErrors - - Args: - msg (str): the exception message - - Keyword Args: - path_to_item (list): a list of keys an indices to get to the - current_item - None if unset - valid_classes (tuple): the primitive classes that current item - should be an instance of - None if unset - key_type (bool): False if our value is a value in a dict - True if it is a key in a dict - False if our item is an item in a list - None if unset - """ - self.path_to_item = path_to_item - self.valid_classes = valid_classes - self.key_type = key_type - full_msg = msg - if path_to_item: - full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) - super(ApiTypeError, self).__init__(full_msg) - - -class ApiValueError(OpenApiException, ValueError): - def __init__(self, msg, path_to_item=None): - """ - Args: - msg (str): the exception message - - Keyword Args: - path_to_item (list) the path to the exception in the - received_data dict. None if unset - """ - - self.path_to_item = path_to_item - full_msg = msg - if path_to_item: - full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) - super(ApiValueError, self).__init__(full_msg) - - -class ApiAttributeError(OpenApiException, AttributeError): - def __init__(self, msg, path_to_item=None): - """ - Raised when an attribute reference or assignment fails. - - Args: - msg (str): the exception message - - Keyword Args: - path_to_item (None/list) the path to the exception in the - received_data dict - """ - self.path_to_item = path_to_item - full_msg = msg - if path_to_item: - full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) - super(ApiAttributeError, self).__init__(full_msg) - - -class ApiKeyError(OpenApiException, KeyError): - def __init__(self, msg, path_to_item=None): - """ - Args: - msg (str): the exception message - - Keyword Args: - path_to_item (None/list) the path to the exception in the - received_data dict - """ - self.path_to_item = path_to_item - full_msg = msg - if path_to_item: - full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) - super(ApiKeyError, self).__init__(full_msg) - - -class ApiException(OpenApiException): - def __init__(self, status=None, reason=None, http_resp=None): - if http_resp: - self.status = http_resp.status - self.reason = http_resp.reason - self.body = http_resp.data - self.headers = http_resp.getheaders() - else: - self.status = status - self.reason = reason - self.body = None - self.headers = None - - def __str__(self): - """Custom error messages for exception""" - error_message = "({0})\n" "Reason: {1}\n".format(self.status, self.reason) - if self.headers: - error_message += "HTTP response headers: {0}\n".format(self.headers) - - if self.body: - error_message += "HTTP response body: {0}\n".format(self.body) - - return error_message - - -class BadRequestException(ApiException): - def __init__(self, status=None, reason=None, http_resp=None): - super(BadRequestException, self).__init__(status, reason, http_resp) - - -class NotFoundException(ApiException): - def __init__(self, status=None, reason=None, http_resp=None): - super(NotFoundException, self).__init__(status, reason, http_resp) - - -class UnauthorizedException(ApiException): - def __init__(self, status=None, reason=None, http_resp=None): - super(UnauthorizedException, self).__init__(status, reason, http_resp) - - -class ForbiddenException(ApiException): - def __init__(self, status=None, reason=None, http_resp=None): - super(ForbiddenException, self).__init__(status, reason, http_resp) - - -class ServiceException(ApiException): - def __init__(self, status=None, reason=None, http_resp=None): - super(ServiceException, self).__init__(status, reason, http_resp) - - -def render_path(path_to_item): - """Returns a string representation of a path""" - result = "" - for pth in path_to_item: - if isinstance(pth, int): - result += "[{0}]".format(pth) - else: - result += "['{0}']".format(pth) - return result diff --git a/jellyfish/_openapi_client/models/__init__.py b/jellyfish/_openapi_client/models/__init__.py index dc1acea..73393a8 100644 --- a/jellyfish/_openapi_client/models/__init__.py +++ b/jellyfish/_openapi_client/models/__init__.py @@ -1,54 +1,65 @@ -# coding: utf-8 +""" Contains all the data models used in inputs/outputs """ -# flake8: noqa -""" - Python API wrapper for Jellyfish Media Server +from .add_component_json_body import AddComponentJsonBody +from .add_peer_json_body import AddPeerJsonBody +from .component_details_response import ComponentDetailsResponse +from .component_file import ComponentFile +from .component_hls import ComponentHLS +from .component_options_file import ComponentOptionsFile +from .component_options_hls import ComponentOptionsHLS +from .component_options_hls_subscribe_mode import ComponentOptionsHLSSubscribeMode +from .component_options_rtsp import ComponentOptionsRTSP +from .component_properties_hls import ComponentPropertiesHLS +from .component_properties_hls_subscribe_mode import ComponentPropertiesHLSSubscribeMode +from .component_properties_rtsp import ComponentPropertiesRTSP +from .component_rtsp import ComponentRTSP +from .error import Error +from .hls_skip import HlsSkip +from .peer import Peer +from .peer_details_response import PeerDetailsResponse +from .peer_details_response_data import PeerDetailsResponseData +from .peer_options_web_rtc import PeerOptionsWebRTC +from .peer_status import PeerStatus +from .recording_list_response import RecordingListResponse +from .room import Room +from .room_config import RoomConfig +from .room_config_video_codec import RoomConfigVideoCodec +from .room_create_details_response import RoomCreateDetailsResponse +from .room_create_details_response_data import RoomCreateDetailsResponseData +from .room_details_response import RoomDetailsResponse +from .rooms_listing_response import RoomsListingResponse +from .s3_credentials import S3Credentials +from .subscription_config import SubscriptionConfig - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -# import models into model package -from jellyfish._openapi_client.models.add_component_request import AddComponentRequest -from jellyfish._openapi_client.models.add_peer_request import AddPeerRequest -from jellyfish._openapi_client.models.component import Component -from jellyfish._openapi_client.models.component_details_response import ( - ComponentDetailsResponse, -) -from jellyfish._openapi_client.models.component_hls import ComponentHLS -from jellyfish._openapi_client.models.component_metadata_hls import ComponentMetadataHLS -from jellyfish._openapi_client.models.component_options import ComponentOptions -from jellyfish._openapi_client.models.component_options_hls import ComponentOptionsHLS -from jellyfish._openapi_client.models.component_options_hlss3 import ( - ComponentOptionsHLSS3, -) -from jellyfish._openapi_client.models.component_options_rtsp import ComponentOptionsRTSP -from jellyfish._openapi_client.models.component_rtsp import ComponentRTSP -from jellyfish._openapi_client.models.error import Error -from jellyfish._openapi_client.models.hls_skip import HlsSkip -from jellyfish._openapi_client.models.peer import Peer -from jellyfish._openapi_client.models.peer_details_response import PeerDetailsResponse -from jellyfish._openapi_client.models.peer_details_response_data import ( - PeerDetailsResponseData, -) -from jellyfish._openapi_client.models.peer_options import PeerOptions -from jellyfish._openapi_client.models.peer_options_web_rtc import PeerOptionsWebRTC -from jellyfish._openapi_client.models.peer_status import PeerStatus -from jellyfish._openapi_client.models.recording_list_response import ( - RecordingListResponse, -) -from jellyfish._openapi_client.models.room import Room -from jellyfish._openapi_client.models.room_config import RoomConfig -from jellyfish._openapi_client.models.room_create_details_response import ( - RoomCreateDetailsResponse, -) -from jellyfish._openapi_client.models.room_create_details_response_data import ( - RoomCreateDetailsResponseData, +__all__ = ( + "AddComponentJsonBody", + "AddPeerJsonBody", + "ComponentDetailsResponse", + "ComponentFile", + "ComponentHLS", + "ComponentOptionsFile", + "ComponentOptionsHLS", + "ComponentOptionsHLSSubscribeMode", + "ComponentOptionsRTSP", + "ComponentPropertiesHLS", + "ComponentPropertiesHLSSubscribeMode", + "ComponentPropertiesRTSP", + "ComponentRTSP", + "Error", + "HlsSkip", + "Peer", + "PeerDetailsResponse", + "PeerDetailsResponseData", + "PeerOptionsWebRTC", + "PeerStatus", + "RecordingListResponse", + "Room", + "RoomConfig", + "RoomConfigVideoCodec", + "RoomCreateDetailsResponse", + "RoomCreateDetailsResponseData", + "RoomDetailsResponse", + "RoomsListingResponse", + "S3Credentials", + "SubscriptionConfig", ) -from jellyfish._openapi_client.models.room_details_response import RoomDetailsResponse -from jellyfish._openapi_client.models.rooms_listing_response import RoomsListingResponse -from jellyfish._openapi_client.models.s3_credentials import S3Credentials -from jellyfish._openapi_client.models.subscription_config import SubscriptionConfig diff --git a/jellyfish/_openapi_client/models/add_component_json_body.py b/jellyfish/_openapi_client/models/add_component_json_body.py new file mode 100644 index 0000000..b0206aa --- /dev/null +++ b/jellyfish/_openapi_client/models/add_component_json_body.py @@ -0,0 +1,130 @@ +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.component_options_file import ComponentOptionsFile + from ..models.component_options_hls import ComponentOptionsHLS + from ..models.component_options_rtsp import ComponentOptionsRTSP + + +T = TypeVar("T", bound="AddComponentJsonBody") + + +@_attrs_define +class AddComponentJsonBody: + """ + Attributes: + type (str): Component type Example: hls. + options (Union['ComponentOptionsFile', 'ComponentOptionsHLS', 'ComponentOptionsRTSP', Unset]): Component- + specific options + """ + + type: str + options: Union[ + "ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset + ] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + from ..models.component_options_hls import ComponentOptionsHLS + from ..models.component_options_rtsp import ComponentOptionsRTSP + + type = self.type + options: Union[Dict[str, Any], Unset] + if isinstance(self.options, Unset): + options = UNSET + + elif isinstance(self.options, ComponentOptionsHLS): + options = self.options.to_dict() + + elif isinstance(self.options, ComponentOptionsRTSP): + options = self.options.to_dict() + + else: + options = self.options.to_dict() + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type, + } + ) + if options is not UNSET: + field_dict["options"] = options + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.component_options_file import ComponentOptionsFile + from ..models.component_options_hls import ComponentOptionsHLS + from ..models.component_options_rtsp import ComponentOptionsRTSP + + d = src_dict.copy() + type = d.pop("type") + + def _parse_options( + data: object, + ) -> Union[ + "ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset + ]: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_options_type_0 = ( + ComponentOptionsHLS.from_dict(data) + ) + + return componentsschemas_component_options_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_options_type_1 = ( + ComponentOptionsRTSP.from_dict(data) + ) + + return componentsschemas_component_options_type_1 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_options_type_2 = ComponentOptionsFile.from_dict( + data + ) + + return componentsschemas_component_options_type_2 + + options = _parse_options(d.pop("options", UNSET)) + + add_component_json_body = cls( + type=type, + options=options, + ) + + add_component_json_body.additional_properties = d + return add_component_json_body + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/add_component_request.py b/jellyfish/_openapi_client/models/add_component_request.py deleted file mode 100644 index 50d2544..0000000 --- a/jellyfish/_openapi_client/models/add_component_request.py +++ /dev/null @@ -1,77 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from typing import Optional -from pydantic import BaseModel, Field, StrictStr -from jellyfish._openapi_client.models.component_options import ComponentOptions - - -class AddComponentRequest(BaseModel): - """ - AddComponentRequest - """ - - options: Optional[ComponentOptions] = None - type: StrictStr = Field(..., description="Component type") - __properties = ["options", "type"] - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) - - @classmethod - def from_json(cls, json_str: str) -> AddComponentRequest: - """Create an instance of AddComponentRequest from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of options - if self.options: - _dict["options"] = self.options.to_dict() - return _dict - - @classmethod - def from_dict(cls, obj: dict) -> AddComponentRequest: - """Create an instance of AddComponentRequest from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return AddComponentRequest.parse_obj(obj) - - _obj = AddComponentRequest.parse_obj( - { - "options": ComponentOptions.from_dict(obj.get("options")) - if obj.get("options") is not None - else None, - "type": obj.get("type"), - } - ) - return _obj diff --git a/jellyfish/_openapi_client/models/add_peer_json_body.py b/jellyfish/_openapi_client/models/add_peer_json_body.py new file mode 100644 index 0000000..325ee74 --- /dev/null +++ b/jellyfish/_openapi_client/models/add_peer_json_body.py @@ -0,0 +1,72 @@ +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.peer_options_web_rtc import PeerOptionsWebRTC + + +T = TypeVar("T", bound="AddPeerJsonBody") + + +@_attrs_define +class AddPeerJsonBody: + """ + Attributes: + options (PeerOptionsWebRTC): Options specific to the WebRTC peer + type (str): Peer type Example: webrtc. + """ + + options: "PeerOptionsWebRTC" + type: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + options = self.options.to_dict() + + type = self.type + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "options": options, + "type": type, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.peer_options_web_rtc import PeerOptionsWebRTC + + d = src_dict.copy() + options = PeerOptionsWebRTC.from_dict(d.pop("options")) + + type = d.pop("type") + + add_peer_json_body = cls( + options=options, + type=type, + ) + + add_peer_json_body.additional_properties = d + return add_peer_json_body + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/add_peer_request.py b/jellyfish/_openapi_client/models/add_peer_request.py deleted file mode 100644 index 5e6453d..0000000 --- a/jellyfish/_openapi_client/models/add_peer_request.py +++ /dev/null @@ -1,76 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from pydantic import BaseModel, Field, StrictStr -from jellyfish._openapi_client.models.peer_options import PeerOptions - - -class AddPeerRequest(BaseModel): - """ - AddPeerRequest - """ - - options: PeerOptions = Field(...) - type: StrictStr = Field(..., description="Peer type") - __properties = ["options", "type"] - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) - - @classmethod - def from_json(cls, json_str: str) -> AddPeerRequest: - """Create an instance of AddPeerRequest from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of options - if self.options: - _dict["options"] = self.options.to_dict() - return _dict - - @classmethod - def from_dict(cls, obj: dict) -> AddPeerRequest: - """Create an instance of AddPeerRequest from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return AddPeerRequest.parse_obj(obj) - - _obj = AddPeerRequest.parse_obj( - { - "options": PeerOptions.from_dict(obj.get("options")) - if obj.get("options") is not None - else None, - "type": obj.get("type"), - } - ) - return _obj diff --git a/jellyfish/_openapi_client/models/component.py b/jellyfish/_openapi_client/models/component.py deleted file mode 100644 index 72413b0..0000000 --- a/jellyfish/_openapi_client/models/component.py +++ /dev/null @@ -1,188 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -from __future__ import annotations -from inspect import getfullargspec -import json -import pprint -import re # noqa: F401 - -from typing import Any, List, Optional -from pydantic import BaseModel, Field, StrictStr, ValidationError, validator -from jellyfish._openapi_client.models.component_hls import ComponentHLS -from jellyfish._openapi_client.models.component_rtsp import ComponentRTSP -from typing import Union, Any, List, TYPE_CHECKING -from pydantic import StrictStr, Field - -COMPONENT_ONE_OF_SCHEMAS = ["ComponentHLS", "ComponentRTSP"] - - -class Component(BaseModel): - """ - Describes component - """ - - # data type: ComponentHLS - oneof_schema_1_validator: Optional[ComponentHLS] = None - # data type: ComponentRTSP - oneof_schema_2_validator: Optional[ComponentRTSP] = None - if TYPE_CHECKING: - actual_instance: Union[ComponentHLS, ComponentRTSP] - else: - actual_instance: Any - one_of_schemas: List[str] = Field(COMPONENT_ONE_OF_SCHEMAS, const=True) - - class Config: - validate_assignment = True - - discriminator_value_class_map = {} - - def __init__(self, *args, **kwargs): - if args: - if len(args) > 1: - raise ValueError( - "If a position argument is used, only 1 is allowed to set `actual_instance`" - ) - if kwargs: - raise ValueError( - "If a position argument is used, keyword arguments cannot be used." - ) - super().__init__(actual_instance=args[0]) - else: - super().__init__(**kwargs) - - @validator("actual_instance") - def actual_instance_must_validate_oneof(cls, v): - instance = Component.construct() - error_messages = [] - match = 0 - # validate data type: ComponentHLS - if not isinstance(v, ComponentHLS): - error_messages.append( - f"Error! Input type `{type(v)}` is not `ComponentHLS`" - ) - else: - match += 1 - # validate data type: ComponentRTSP - if not isinstance(v, ComponentRTSP): - error_messages.append( - f"Error! Input type `{type(v)}` is not `ComponentRTSP`" - ) - else: - match += 1 - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when setting `actual_instance` in Component with oneOf schemas: ComponentHLS, ComponentRTSP. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when setting `actual_instance` in Component with oneOf schemas: ComponentHLS, ComponentRTSP. Details: " - + ", ".join(error_messages) - ) - else: - return v - - @classmethod - def from_dict(cls, obj: dict) -> Component: - return cls.from_json(json.dumps(obj)) - - @classmethod - def from_json(cls, json_str: str) -> Component: - """Returns the object represented by the json string""" - instance = Component.construct() - error_messages = [] - match = 0 - - # use oneOf discriminator to lookup the data type - _data_type = json.loads(json_str).get("type") - if not _data_type: - raise ValueError( - "Failed to lookup data type from the field `type` in the input." - ) - - # check if data type is `ComponentHLS` - if _data_type == "ComponentHLS": - instance.actual_instance = ComponentHLS.from_json(json_str) - return instance - - # check if data type is `ComponentRTSP` - if _data_type == "ComponentRTSP": - instance.actual_instance = ComponentRTSP.from_json(json_str) - return instance - - # check if data type is `ComponentHLS` - if _data_type == "hls": - instance.actual_instance = ComponentHLS.from_json(json_str) - return instance - - # check if data type is `ComponentRTSP` - if _data_type == "rtsp": - instance.actual_instance = ComponentRTSP.from_json(json_str) - return instance - - # deserialize data into ComponentHLS - try: - instance.actual_instance = ComponentHLS.from_json(json_str) - match += 1 - except (ValidationError, ValueError) as e: - error_messages.append(str(e)) - # deserialize data into ComponentRTSP - try: - instance.actual_instance = ComponentRTSP.from_json(json_str) - match += 1 - except (ValidationError, ValueError) as e: - error_messages.append(str(e)) - - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when deserializing the JSON string into Component with oneOf schemas: ComponentHLS, ComponentRTSP. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when deserializing the JSON string into Component with oneOf schemas: ComponentHLS, ComponentRTSP. Details: " - + ", ".join(error_messages) - ) - else: - return instance - - def to_json(self) -> str: - """Returns the JSON representation of the actual instance""" - if self.actual_instance is None: - return "null" - - to_json = getattr(self.actual_instance, "to_json", None) - if callable(to_json): - return self.actual_instance.to_json() - else: - return json.dumps(self.actual_instance) - - def to_dict(self) -> dict: - """Returns the dict representation of the actual instance""" - if self.actual_instance is None: - return None - - to_dict = getattr(self.actual_instance, "to_dict", None) - if callable(to_dict): - return self.actual_instance.to_dict() - else: - # primitive type - return self.actual_instance - - def to_str(self) -> str: - """Returns the string representation of the actual instance""" - return pprint.pformat(self.dict()) diff --git a/jellyfish/_openapi_client/models/component_details_response.py b/jellyfish/_openapi_client/models/component_details_response.py index 5cac9bf..018b997 100644 --- a/jellyfish/_openapi_client/models/component_details_response.py +++ b/jellyfish/_openapi_client/models/component_details_response.py @@ -1,74 +1,107 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.component_file import ComponentFile + from ..models.component_hls import ComponentHLS + from ..models.component_rtsp import ComponentRTSP - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="ComponentDetailsResponse") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class ComponentDetailsResponse: + """Response containing component details -from pydantic import BaseModel, Field -from jellyfish._openapi_client.models.component import Component + Attributes: + data (Union['ComponentFile', 'ComponentHLS', 'ComponentRTSP']): Describes component + """ + data: Union["ComponentFile", "ComponentHLS", "ComponentRTSP"] + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class ComponentDetailsResponse(BaseModel): - """ - Response containing component details - """ + def to_dict(self) -> Dict[str, Any]: + from ..models.component_hls import ComponentHLS + from ..models.component_rtsp import ComponentRTSP - data: Component = Field(...) - __properties = ["data"] + data: Dict[str, Any] - class Config: - """Pydantic configuration""" + if isinstance(self.data, ComponentHLS): + data = self.data.to_dict() - allow_population_by_field_name = True - validate_assignment = True + elif isinstance(self.data, ComponentRTSP): + data = self.data.to_dict() - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + else: + data = self.data.to_dict() - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) - @classmethod - def from_json(cls, json_str: str) -> ComponentDetailsResponse: - """Create an instance of ComponentDetailsResponse from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of data - if self.data: - _dict["data"] = self.data.to_dict() - return _dict + return field_dict @classmethod - def from_dict(cls, obj: dict) -> ComponentDetailsResponse: - """Create an instance of ComponentDetailsResponse from a dict""" - if obj is None: - return None + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.component_file import ComponentFile + from ..models.component_hls import ComponentHLS + from ..models.component_rtsp import ComponentRTSP + + d = src_dict.copy() + + def _parse_data( + data: object, + ) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_0 = ComponentHLS.from_dict(data) + + return componentsschemas_component_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_1 = ComponentRTSP.from_dict(data) + + return componentsschemas_component_type_1 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_2 = ComponentFile.from_dict(data) + + return componentsschemas_component_type_2 + + data = _parse_data(d.pop("data")) + + component_details_response = cls( + data=data, + ) - if not isinstance(obj, dict): - return ComponentDetailsResponse.parse_obj(obj) + component_details_response.additional_properties = d + return component_details_response - _obj = ComponentDetailsResponse.parse_obj( - { - "data": Component.from_dict(obj.get("data")) - if obj.get("data") is not None - else None - } - ) - return _obj + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_file.py b/jellyfish/_openapi_client/models/component_file.py new file mode 100644 index 0000000..4b0a8be --- /dev/null +++ b/jellyfish/_openapi_client/models/component_file.py @@ -0,0 +1,66 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ComponentFile") + + +@_attrs_define +class ComponentFile: + """Describes the File component + + Attributes: + id (str): Assigned component ID Example: component-1. + type (str): Component type Example: file. + """ + + id: str + type: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + id = self.id + type = self.type + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "type": type, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id") + + type = d.pop("type") + + component_file = cls( + id=id, + type=type, + ) + + component_file.additional_properties = d + return component_file + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_hls.py b/jellyfish/_openapi_client/models/component_hls.py index acedabe..ac2449e 100644 --- a/jellyfish/_openapi_client/models/component_hls.py +++ b/jellyfish/_openapi_client/models/component_hls.py @@ -1,78 +1,80 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.component_properties_hls import ComponentPropertiesHLS - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="ComponentHLS") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class ComponentHLS: + """Describes the HLS component -from pydantic import BaseModel, Field, StrictStr -from jellyfish._openapi_client.models.component_metadata_hls import ComponentMetadataHLS - - -class ComponentHLS(BaseModel): - """ - Describes HLS component + Attributes: + id (str): Assigned component ID Example: component-1. + properties (ComponentPropertiesHLS): Properties specific to the HLS component + type (str): Component type Example: hls. """ - id: StrictStr = Field(..., description="Assigned component ID") - metadata: ComponentMetadataHLS = Field(...) - type: StrictStr = Field(..., description="Component type") - __properties = ["id", "metadata", "type"] + id: str + properties: "ComponentPropertiesHLS" + type: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) - class Config: - """Pydantic configuration""" + def to_dict(self) -> Dict[str, Any]: + id = self.id + properties = self.properties.to_dict() - allow_population_by_field_name = True - validate_assignment = True + type = self.type - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "properties": properties, + "type": type, + } + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + return field_dict @classmethod - def from_json(cls, json_str: str) -> ComponentHLS: - """Create an instance of ComponentHLS from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of metadata - if self.metadata: - _dict["metadata"] = self.metadata.to_dict() - return _dict + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.component_properties_hls import ComponentPropertiesHLS - @classmethod - def from_dict(cls, obj: dict) -> ComponentHLS: - """Create an instance of ComponentHLS from a dict""" - if obj is None: - return None + d = src_dict.copy() + id = d.pop("id") - if not isinstance(obj, dict): - return ComponentHLS.parse_obj(obj) + properties = ComponentPropertiesHLS.from_dict(d.pop("properties")) - _obj = ComponentHLS.parse_obj( - { - "id": obj.get("id"), - "metadata": ComponentMetadataHLS.from_dict(obj.get("metadata")) - if obj.get("metadata") is not None - else None, - "type": obj.get("type"), - } + type = d.pop("type") + + component_hls = cls( + id=id, + properties=properties, + type=type, ) - return _obj + + component_hls.additional_properties = d + return component_hls + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_metadata_hls.py b/jellyfish/_openapi_client/models/component_metadata_hls.py deleted file mode 100644 index 68f0936..0000000 --- a/jellyfish/_openapi_client/models/component_metadata_hls.py +++ /dev/null @@ -1,112 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from typing import Optional -from pydantic import BaseModel, Field, StrictBool, StrictInt, StrictStr, validator - - -class ComponentMetadataHLS(BaseModel): - """ - Metadata specific to the HLS component - """ - - low_latency: StrictBool = Field( - ..., alias="lowLatency", description="Whether the component uses LL-HLS" - ) - persistent: StrictBool = Field( - ..., description="Whether the video is stored after end of stream" - ) - playable: StrictBool = Field( - ..., description="Whether the generated HLS playlist is playable" - ) - subscribe_mode: StrictStr = Field( - ..., - alias="subscribeMode", - description="Whether the HLS component should subscribe to tracks automatically or manually", - ) - target_window_duration: Optional[StrictInt] = Field( - ..., - alias="targetWindowDuration", - description="Duration of stream available for viewer", - ) - __properties = [ - "lowLatency", - "persistent", - "playable", - "subscribeMode", - "targetWindowDuration", - ] - - @validator("subscribe_mode") - def subscribe_mode_validate_enum(cls, value): - """Validates the enum""" - if value not in ("auto", "manual"): - raise ValueError("must be one of enum values ('auto', 'manual')") - return value - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) - - @classmethod - def from_json(cls, json_str: str) -> ComponentMetadataHLS: - """Create an instance of ComponentMetadataHLS from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # set to None if target_window_duration (nullable) is None - # and __fields_set__ contains the field - if ( - self.target_window_duration is None - and "target_window_duration" in self.__fields_set__ - ): - _dict["targetWindowDuration"] = None - - return _dict - - @classmethod - def from_dict(cls, obj: dict) -> ComponentMetadataHLS: - """Create an instance of ComponentMetadataHLS from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return ComponentMetadataHLS.parse_obj(obj) - - _obj = ComponentMetadataHLS.parse_obj( - { - "low_latency": obj.get("lowLatency"), - "persistent": obj.get("persistent"), - "playable": obj.get("playable"), - "subscribe_mode": obj.get("subscribeMode"), - "target_window_duration": obj.get("targetWindowDuration"), - } - ) - return _obj diff --git a/jellyfish/_openapi_client/models/component_options.py b/jellyfish/_openapi_client/models/component_options.py deleted file mode 100644 index 26e3dda..0000000 --- a/jellyfish/_openapi_client/models/component_options.py +++ /dev/null @@ -1,159 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -from __future__ import annotations -from inspect import getfullargspec -import json -import pprint -import re # noqa: F401 - -from typing import Any, List, Optional -from pydantic import BaseModel, Field, StrictStr, ValidationError, validator -from jellyfish._openapi_client.models.component_options_hls import ComponentOptionsHLS -from jellyfish._openapi_client.models.component_options_rtsp import ComponentOptionsRTSP -from typing import Union, Any, List, TYPE_CHECKING -from pydantic import StrictStr, Field - -COMPONENTOPTIONS_ONE_OF_SCHEMAS = ["ComponentOptionsHLS", "ComponentOptionsRTSP"] - - -class ComponentOptions(BaseModel): - """ - Component-specific options - """ - - # data type: ComponentOptionsHLS - oneof_schema_1_validator: Optional[ComponentOptionsHLS] = None - # data type: ComponentOptionsRTSP - oneof_schema_2_validator: Optional[ComponentOptionsRTSP] = None - if TYPE_CHECKING: - actual_instance: Union[ComponentOptionsHLS, ComponentOptionsRTSP] - else: - actual_instance: Any - one_of_schemas: List[str] = Field(COMPONENTOPTIONS_ONE_OF_SCHEMAS, const=True) - - class Config: - validate_assignment = True - - def __init__(self, *args, **kwargs): - if args: - if len(args) > 1: - raise ValueError( - "If a position argument is used, only 1 is allowed to set `actual_instance`" - ) - if kwargs: - raise ValueError( - "If a position argument is used, keyword arguments cannot be used." - ) - super().__init__(actual_instance=args[0]) - else: - super().__init__(**kwargs) - - @validator("actual_instance") - def actual_instance_must_validate_oneof(cls, v): - instance = ComponentOptions.construct() - error_messages = [] - match = 0 - # validate data type: ComponentOptionsHLS - if not isinstance(v, ComponentOptionsHLS): - error_messages.append( - f"Error! Input type `{type(v)}` is not `ComponentOptionsHLS`" - ) - else: - match += 1 - # validate data type: ComponentOptionsRTSP - if not isinstance(v, ComponentOptionsRTSP): - error_messages.append( - f"Error! Input type `{type(v)}` is not `ComponentOptionsRTSP`" - ) - else: - match += 1 - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when setting `actual_instance` in ComponentOptions with oneOf schemas: ComponentOptionsHLS, ComponentOptionsRTSP. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when setting `actual_instance` in ComponentOptions with oneOf schemas: ComponentOptionsHLS, ComponentOptionsRTSP. Details: " - + ", ".join(error_messages) - ) - else: - return v - - @classmethod - def from_dict(cls, obj: dict) -> ComponentOptions: - return cls.from_json(json.dumps(obj)) - - @classmethod - def from_json(cls, json_str: str) -> ComponentOptions: - """Returns the object represented by the json string""" - instance = ComponentOptions.construct() - error_messages = [] - match = 0 - - # deserialize data into ComponentOptionsHLS - try: - instance.actual_instance = ComponentOptionsHLS.from_json(json_str) - match += 1 - except (ValidationError, ValueError) as e: - error_messages.append(str(e)) - # deserialize data into ComponentOptionsRTSP - try: - instance.actual_instance = ComponentOptionsRTSP.from_json(json_str) - match += 1 - except (ValidationError, ValueError) as e: - error_messages.append(str(e)) - - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when deserializing the JSON string into ComponentOptions with oneOf schemas: ComponentOptionsHLS, ComponentOptionsRTSP. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when deserializing the JSON string into ComponentOptions with oneOf schemas: ComponentOptionsHLS, ComponentOptionsRTSP. Details: " - + ", ".join(error_messages) - ) - else: - return instance - - def to_json(self) -> str: - """Returns the JSON representation of the actual instance""" - if self.actual_instance is None: - return "null" - - to_json = getattr(self.actual_instance, "to_json", None) - if callable(to_json): - return self.actual_instance.to_json() - else: - return json.dumps(self.actual_instance) - - def to_dict(self) -> dict: - """Returns the dict representation of the actual instance""" - if self.actual_instance is None: - return None - - to_dict = getattr(self.actual_instance, "to_dict", None) - if callable(to_dict): - return self.actual_instance.to_dict() - else: - # primitive type - return self.actual_instance - - def to_str(self) -> str: - """Returns the string representation of the actual instance""" - return pprint.pformat(self.dict()) diff --git a/jellyfish/_openapi_client/models/component_options_file.py b/jellyfish/_openapi_client/models/component_options_file.py new file mode 100644 index 0000000..b707a90 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_options_file.py @@ -0,0 +1,60 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ComponentOptionsFile") + + +@_attrs_define +class ComponentOptionsFile: + """Options specific to the File component + + Attributes: + file_path (str): Path to track file. Must be either OPUS encapsulated in Ogg or raw h264 Example: + /root/video.h264. + """ + + file_path: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + file_path = self.file_path + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "filePath": file_path, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + file_path = d.pop("filePath") + + component_options_file = cls( + file_path=file_path, + ) + + component_options_file.additional_properties = d + return component_options_file + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_options_hls.py b/jellyfish/_openapi_client/models/component_options_hls.py index 3f31589..7615311 100644 --- a/jellyfish/_openapi_client/models/component_options_hls.py +++ b/jellyfish/_openapi_client/models/component_options_hls.py @@ -1,132 +1,122 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 +from ..models.component_options_hls_subscribe_mode import ( + ComponentOptionsHLSSubscribeMode, +) +from ..types import UNSET, Unset +if TYPE_CHECKING: + from ..models.s3_credentials import S3Credentials -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +T = TypeVar("T", bound="ComponentOptionsHLS") -from typing import Optional -from pydantic import BaseModel, Field, StrictBool, StrictInt, StrictStr, validator -from jellyfish._openapi_client.models.component_options_hlss3 import ( - ComponentOptionsHLSS3, -) +@_attrs_define +class ComponentOptionsHLS: + """Options specific to the HLS component -class ComponentOptionsHLS(BaseModel): + Attributes: + low_latency (Union[Unset, bool]): Whether the component should use LL-HLS + persistent (Union[Unset, bool]): Whether the video is stored after end of stream + s3 (Union[Unset, None, S3Credentials]): An AWS S3 credential that will be used to send HLS stream. The stream + will only be uploaded if credentials are provided + subscribe_mode (Union[Unset, ComponentOptionsHLSSubscribeMode]): Whether the HLS component should subscribe to + tracks automatically or manually. Default: ComponentOptionsHLSSubscribeMode.AUTO. + target_window_duration (Union[Unset, None, int]): Duration of stream available for viewer """ - Options specific to the HLS component - """ - - low_latency: Optional[StrictBool] = Field( - False, alias="lowLatency", description="Whether the component should use LL-HLS" - ) - persistent: Optional[StrictBool] = Field( - False, description="Whether the video is stored after end of stream" - ) - s3: Optional[ComponentOptionsHLSS3] = None - subscribe_mode: Optional[StrictStr] = Field( - "auto", - alias="subscribeMode", - description="Whether the HLS component should subscribe to tracks automatically or manually.", - ) - target_window_duration: Optional[StrictInt] = Field( - None, - alias="targetWindowDuration", - description="Duration of stream available for viewer", - ) - __properties = [ - "lowLatency", - "persistent", - "s3", - "subscribeMode", - "targetWindowDuration", - ] - - @validator("subscribe_mode") - def subscribe_mode_validate_enum(cls, value): - """Validates the enum""" - if value is None: - return value - - if value not in ("auto", "manual"): - raise ValueError("must be one of enum values ('auto', 'manual')") - return value - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) - @classmethod - def from_json(cls, json_str: str) -> ComponentOptionsHLS: - """Create an instance of ComponentOptionsHLS from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of s3 - if self.s3: - _dict["s3"] = self.s3.to_dict() - # set to None if s3 (nullable) is None - # and __fields_set__ contains the field - if self.s3 is None and "s3" in self.__fields_set__: - _dict["s3"] = None - - # set to None if target_window_duration (nullable) is None - # and __fields_set__ contains the field - if ( - self.target_window_duration is None - and "target_window_duration" in self.__fields_set__ - ): - _dict["targetWindowDuration"] = None - - return _dict + low_latency: Union[Unset, bool] = False + persistent: Union[Unset, bool] = False + s3: Union[Unset, None, "S3Credentials"] = UNSET + subscribe_mode: Union[ + Unset, ComponentOptionsHLSSubscribeMode + ] = ComponentOptionsHLSSubscribeMode.AUTO + target_window_duration: Union[Unset, None, int] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + low_latency = self.low_latency + persistent = self.persistent + s3: Union[Unset, None, Dict[str, Any]] = UNSET + if not isinstance(self.s3, Unset): + s3 = self.s3.to_dict() if self.s3 else None + + subscribe_mode: Union[Unset, str] = UNSET + if not isinstance(self.subscribe_mode, Unset): + subscribe_mode = self.subscribe_mode.value + + target_window_duration = self.target_window_duration + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if low_latency is not UNSET: + field_dict["lowLatency"] = low_latency + if persistent is not UNSET: + field_dict["persistent"] = persistent + if s3 is not UNSET: + field_dict["s3"] = s3 + if subscribe_mode is not UNSET: + field_dict["subscribeMode"] = subscribe_mode + if target_window_duration is not UNSET: + field_dict["targetWindowDuration"] = target_window_duration + + return field_dict @classmethod - def from_dict(cls, obj: dict) -> ComponentOptionsHLS: - """Create an instance of ComponentOptionsHLS from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return ComponentOptionsHLS.parse_obj(obj) - - _obj = ComponentOptionsHLS.parse_obj( - { - "low_latency": obj.get("lowLatency") - if obj.get("lowLatency") is not None - else False, - "persistent": obj.get("persistent") - if obj.get("persistent") is not None - else False, - "s3": ComponentOptionsHLSS3.from_dict(obj.get("s3")) - if obj.get("s3") is not None - else None, - "subscribe_mode": obj.get("subscribeMode") - if obj.get("subscribeMode") is not None - else "auto", - "target_window_duration": obj.get("targetWindowDuration"), - } + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.s3_credentials import S3Credentials + + d = src_dict.copy() + low_latency = d.pop("lowLatency", UNSET) + + persistent = d.pop("persistent", UNSET) + + _s3 = d.pop("s3", UNSET) + s3: Union[Unset, None, S3Credentials] + if _s3 is None: + s3 = None + elif isinstance(_s3, Unset): + s3 = UNSET + else: + s3 = S3Credentials.from_dict(_s3) + + _subscribe_mode = d.pop("subscribeMode", UNSET) + subscribe_mode: Union[Unset, ComponentOptionsHLSSubscribeMode] + if isinstance(_subscribe_mode, Unset): + subscribe_mode = UNSET + else: + subscribe_mode = ComponentOptionsHLSSubscribeMode(_subscribe_mode) + + target_window_duration = d.pop("targetWindowDuration", UNSET) + + component_options_hls = cls( + low_latency=low_latency, + persistent=persistent, + s3=s3, + subscribe_mode=subscribe_mode, + target_window_duration=target_window_duration, ) - return _obj + + component_options_hls.additional_properties = d + return component_options_hls + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py b/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py new file mode 100644 index 0000000..99b23e7 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class ComponentOptionsHLSSubscribeMode(str, Enum): + AUTO = "auto" + MANUAL = "manual" + + def __str__(self) -> str: + return str(self.value) diff --git a/jellyfish/_openapi_client/models/component_options_hlss3.py b/jellyfish/_openapi_client/models/component_options_hlss3.py deleted file mode 100644 index cb146dd..0000000 --- a/jellyfish/_openapi_client/models/component_options_hlss3.py +++ /dev/null @@ -1,149 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -from __future__ import annotations -from inspect import getfullargspec -import json -import pprint -import re # noqa: F401 - -from typing import Any, List, Optional -from pydantic import BaseModel, Field, StrictStr, ValidationError, validator -from jellyfish._openapi_client.models.s3_credentials import S3Credentials -from typing import Union, Any, List, TYPE_CHECKING -from pydantic import StrictStr, Field - -COMPONENTOPTIONSHLSS3_ONE_OF_SCHEMAS = ["S3Credentials"] - - -class ComponentOptionsHLSS3(BaseModel): - """ - Credentials to AWS S3 bucket. - """ - - # data type: S3Credentials - oneof_schema_1_validator: Optional[S3Credentials] = None - if TYPE_CHECKING: - actual_instance: Union[S3Credentials] - else: - actual_instance: Any - one_of_schemas: List[str] = Field(COMPONENTOPTIONSHLSS3_ONE_OF_SCHEMAS, const=True) - - class Config: - validate_assignment = True - - def __init__(self, *args, **kwargs): - if args: - if len(args) > 1: - raise ValueError( - "If a position argument is used, only 1 is allowed to set `actual_instance`" - ) - if kwargs: - raise ValueError( - "If a position argument is used, keyword arguments cannot be used." - ) - super().__init__(actual_instance=args[0]) - else: - super().__init__(**kwargs) - - @validator("actual_instance") - def actual_instance_must_validate_oneof(cls, v): - if v is None: - return v - - instance = ComponentOptionsHLSS3.construct() - error_messages = [] - match = 0 - # validate data type: S3Credentials - if not isinstance(v, S3Credentials): - error_messages.append( - f"Error! Input type `{type(v)}` is not `S3Credentials`" - ) - else: - match += 1 - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when setting `actual_instance` in ComponentOptionsHLSS3 with oneOf schemas: S3Credentials. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when setting `actual_instance` in ComponentOptionsHLSS3 with oneOf schemas: S3Credentials. Details: " - + ", ".join(error_messages) - ) - else: - return v - - @classmethod - def from_dict(cls, obj: dict) -> ComponentOptionsHLSS3: - return cls.from_json(json.dumps(obj)) - - @classmethod - def from_json(cls, json_str: str) -> ComponentOptionsHLSS3: - """Returns the object represented by the json string""" - instance = ComponentOptionsHLSS3.construct() - if json_str is None: - return instance - - error_messages = [] - match = 0 - - # deserialize data into S3Credentials - try: - instance.actual_instance = S3Credentials.from_json(json_str) - match += 1 - except (ValidationError, ValueError) as e: - error_messages.append(str(e)) - - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when deserializing the JSON string into ComponentOptionsHLSS3 with oneOf schemas: S3Credentials. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when deserializing the JSON string into ComponentOptionsHLSS3 with oneOf schemas: S3Credentials. Details: " - + ", ".join(error_messages) - ) - else: - return instance - - def to_json(self) -> str: - """Returns the JSON representation of the actual instance""" - if self.actual_instance is None: - return "null" - - to_json = getattr(self.actual_instance, "to_json", None) - if callable(to_json): - return self.actual_instance.to_json() - else: - return json.dumps(self.actual_instance) - - def to_dict(self) -> dict: - """Returns the dict representation of the actual instance""" - if self.actual_instance is None: - return None - - to_dict = getattr(self.actual_instance, "to_dict", None) - if callable(to_dict): - return self.actual_instance.to_dict() - else: - # primitive type - return self.actual_instance - - def to_str(self) -> str: - """Returns the string representation of the actual instance""" - return pprint.pformat(self.dict()) diff --git a/jellyfish/_openapi_client/models/component_options_rtsp.py b/jellyfish/_openapi_client/models/component_options_rtsp.py index 7f6983f..8c536cc 100644 --- a/jellyfish/_openapi_client/models/component_options_rtsp.py +++ b/jellyfish/_openapi_client/models/component_options_rtsp.py @@ -1,107 +1,95 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar, Union -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +from ..types import UNSET, Unset - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="ComponentOptionsRTSP") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class ComponentOptionsRTSP: + """Options specific to the RTSP component - -from typing import Optional -from pydantic import BaseModel, Field, StrictBool, StrictStr, conint - - -class ComponentOptionsRTSP(BaseModel): - """ - Options specific to the RTSP component + Attributes: + source_uri (str): URI of RTSP source stream Example: rtsp://localhost:554/stream. + keep_alive_interval (Union[Unset, int]): Interval (in ms) in which keep-alive RTSP messages will be sent to the + remote stream source Default: 15000. + pierce_nat (Union[Unset, bool]): Whether to attempt to create client-side NAT binding by sending an empty + datagram from client to source, after the completion of RTSP setup Default: True. + reconnect_delay (Union[Unset, int]): Delay (in ms) between successive reconnect attempts Default: 15000. + rtp_port (Union[Unset, int]): Local port RTP stream will be received at Default: 20000. """ - keep_alive_interval: Optional[conint(strict=True, ge=0)] = Field( - 15000, - alias="keepAliveInterval", - description="Interval (in ms) in which keep-alive RTSP messages will be sent to the remote stream source", - ) - pierce_nat: Optional[StrictBool] = Field( - True, - alias="pierceNat", - description="Whether to attempt to create client-side NAT binding by sending an empty datagram from client to source, after the completion of RTSP setup", - ) - reconnect_delay: Optional[conint(strict=True, ge=0)] = Field( - 15000, - alias="reconnectDelay", - description="Delay (in ms) between successive reconnect attempts", - ) - rtp_port: Optional[conint(strict=True, le=65535, ge=1)] = Field( - 20000, alias="rtpPort", description="Local port RTP stream will be received at" - ) - source_uri: StrictStr = Field( - ..., alias="sourceUri", description="URI of RTSP source stream" - ) - __properties = [ - "keepAliveInterval", - "pierceNat", - "reconnectDelay", - "rtpPort", - "sourceUri", - ] - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + source_uri: str + keep_alive_interval: Union[Unset, int] = 15000 + pierce_nat: Union[Unset, bool] = True + reconnect_delay: Union[Unset, int] = 15000 + rtp_port: Union[Unset, int] = 20000 + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + source_uri = self.source_uri + keep_alive_interval = self.keep_alive_interval + pierce_nat = self.pierce_nat + reconnect_delay = self.reconnect_delay + rtp_port = self.rtp_port + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "sourceUri": source_uri, + } + ) + if keep_alive_interval is not UNSET: + field_dict["keepAliveInterval"] = keep_alive_interval + if pierce_nat is not UNSET: + field_dict["pierceNat"] = pierce_nat + if reconnect_delay is not UNSET: + field_dict["reconnectDelay"] = reconnect_delay + if rtp_port is not UNSET: + field_dict["rtpPort"] = rtp_port + + return field_dict @classmethod - def from_json(cls, json_str: str) -> ComponentOptionsRTSP: - """Create an instance of ComponentOptionsRTSP from a JSON string""" - return cls.from_dict(json.loads(json_str)) + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + source_uri = d.pop("sourceUri") - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + keep_alive_interval = d.pop("keepAliveInterval", UNSET) - @classmethod - def from_dict(cls, obj: dict) -> ComponentOptionsRTSP: - """Create an instance of ComponentOptionsRTSP from a dict""" - if obj is None: - return None + pierce_nat = d.pop("pierceNat", UNSET) - if not isinstance(obj, dict): - return ComponentOptionsRTSP.parse_obj(obj) + reconnect_delay = d.pop("reconnectDelay", UNSET) - _obj = ComponentOptionsRTSP.parse_obj( - { - "keep_alive_interval": obj.get("keepAliveInterval") - if obj.get("keepAliveInterval") is not None - else 15000, - "pierce_nat": obj.get("pierceNat") - if obj.get("pierceNat") is not None - else True, - "reconnect_delay": obj.get("reconnectDelay") - if obj.get("reconnectDelay") is not None - else 15000, - "rtp_port": obj.get("rtpPort") - if obj.get("rtpPort") is not None - else 20000, - "source_uri": obj.get("sourceUri"), - } + rtp_port = d.pop("rtpPort", UNSET) + + component_options_rtsp = cls( + source_uri=source_uri, + keep_alive_interval=keep_alive_interval, + pierce_nat=pierce_nat, + reconnect_delay=reconnect_delay, + rtp_port=rtp_port, ) - return _obj + + component_options_rtsp.additional_properties = d + return component_options_rtsp + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_properties_hls.py b/jellyfish/_openapi_client/models/component_properties_hls.py new file mode 100644 index 0000000..f0bd133 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_properties_hls.py @@ -0,0 +1,93 @@ +from typing import Any, Dict, List, Optional, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.component_properties_hls_subscribe_mode import ( + ComponentPropertiesHLSSubscribeMode, +) + +T = TypeVar("T", bound="ComponentPropertiesHLS") + + +@_attrs_define +class ComponentPropertiesHLS: + """Properties specific to the HLS component + + Attributes: + low_latency (bool): Whether the component uses LL-HLS + persistent (bool): Whether the video is stored after end of stream + playable (bool): Whether the generated HLS playlist is playable + subscribe_mode (ComponentPropertiesHLSSubscribeMode): Whether the HLS component should subscribe to tracks + automatically or manually + target_window_duration (Optional[int]): Duration of stream available for viewer + """ + + low_latency: bool + persistent: bool + playable: bool + subscribe_mode: ComponentPropertiesHLSSubscribeMode + target_window_duration: Optional[int] + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + low_latency = self.low_latency + persistent = self.persistent + playable = self.playable + subscribe_mode = self.subscribe_mode.value + + target_window_duration = self.target_window_duration + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "lowLatency": low_latency, + "persistent": persistent, + "playable": playable, + "subscribeMode": subscribe_mode, + "targetWindowDuration": target_window_duration, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + low_latency = d.pop("lowLatency") + + persistent = d.pop("persistent") + + playable = d.pop("playable") + + subscribe_mode = ComponentPropertiesHLSSubscribeMode(d.pop("subscribeMode")) + + target_window_duration = d.pop("targetWindowDuration") + + component_properties_hls = cls( + low_latency=low_latency, + persistent=persistent, + playable=playable, + subscribe_mode=subscribe_mode, + target_window_duration=target_window_duration, + ) + + component_properties_hls.additional_properties = d + return component_properties_hls + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py b/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py new file mode 100644 index 0000000..09c6719 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class ComponentPropertiesHLSSubscribeMode(str, Enum): + AUTO = "auto" + MANUAL = "manual" + + def __str__(self) -> str: + return str(self.value) diff --git a/jellyfish/_openapi_client/models/component_properties_rtsp.py b/jellyfish/_openapi_client/models/component_properties_rtsp.py new file mode 100644 index 0000000..635e178 --- /dev/null +++ b/jellyfish/_openapi_client/models/component_properties_rtsp.py @@ -0,0 +1,44 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ComponentPropertiesRTSP") + + +@_attrs_define +class ComponentPropertiesRTSP: + """Properties specific to the RTSP component""" + + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + component_properties_rtsp = cls() + + component_properties_rtsp.additional_properties = d + return component_properties_rtsp + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/component_rtsp.py b/jellyfish/_openapi_client/models/component_rtsp.py index dc6797c..a25c60d 100644 --- a/jellyfish/_openapi_client/models/component_rtsp.py +++ b/jellyfish/_openapi_client/models/component_rtsp.py @@ -1,75 +1,80 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.component_properties_rtsp import ComponentPropertiesRTSP - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="ComponentRTSP") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class ComponentRTSP: + """Describes the RTSP component -from typing import Any, Dict -from pydantic import BaseModel, Field, StrictStr - - -class ComponentRTSP(BaseModel): - """ - Describes RTSP component + Attributes: + id (str): Assigned component ID Example: component-1. + properties (ComponentPropertiesRTSP): Properties specific to the RTSP component + type (str): Component type Example: hls. """ - id: StrictStr = Field(..., description="Assigned component ID") - metadata: Dict[str, Any] = Field( - ..., description="Metadata specific to the RTSP component" - ) - type: StrictStr = Field(..., description="Component type") - __properties = ["id", "metadata", "type"] + id: str + properties: "ComponentPropertiesRTSP" + type: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) - class Config: - """Pydantic configuration""" + def to_dict(self) -> Dict[str, Any]: + id = self.id + properties = self.properties.to_dict() - allow_population_by_field_name = True - validate_assignment = True + type = self.type - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "properties": properties, + "type": type, + } + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + return field_dict @classmethod - def from_json(cls, json_str: str) -> ComponentRTSP: - """Create an instance of ComponentRTSP from a JSON string""" - return cls.from_dict(json.loads(json_str)) + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.component_properties_rtsp import ComponentPropertiesRTSP - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + d = src_dict.copy() + id = d.pop("id") - @classmethod - def from_dict(cls, obj: dict) -> ComponentRTSP: - """Create an instance of ComponentRTSP from a dict""" - if obj is None: - return None + properties = ComponentPropertiesRTSP.from_dict(d.pop("properties")) - if not isinstance(obj, dict): - return ComponentRTSP.parse_obj(obj) + type = d.pop("type") - _obj = ComponentRTSP.parse_obj( - { - "id": obj.get("id"), - "metadata": obj.get("metadata"), - "type": obj.get("type"), - } + component_rtsp = cls( + id=id, + properties=properties, + type=type, ) - return _obj + + component_rtsp.additional_properties = d + return component_rtsp + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/error.py b/jellyfish/_openapi_client/models/error.py index cdb9dcc..0d246c2 100644 --- a/jellyfish/_openapi_client/models/error.py +++ b/jellyfish/_openapi_client/models/error.py @@ -1,64 +1,59 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +T = TypeVar("T", bound="Error") - Do not edit the class manually. -""" # noqa: E501 +@_attrs_define +class Error: + """Error message -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from pydantic import BaseModel, Field, StrictStr + Attributes: + errors (str): Error details Example: Token has expired. + """ + errors: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class Error(BaseModel): - """ - Error message - """ + def to_dict(self) -> Dict[str, Any]: + errors = self.errors - errors: StrictStr = Field(..., description="Error details") - __properties = ["errors"] + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "errors": errors, + } + ) - class Config: - """Pydantic configuration""" + return field_dict - allow_population_by_field_name = True - validate_assignment = True + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + errors = d.pop("errors") - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + error = cls( + errors=errors, + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + error.additional_properties = d + return error - @classmethod - def from_json(cls, json_str: str) -> Error: - """Create an instance of Error from a JSON string""" - return cls.from_dict(json.loads(json_str)) + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - @classmethod - def from_dict(cls, obj: dict) -> Error: - """Create an instance of Error from a dict""" - if obj is None: - return None + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value - if not isinstance(obj, dict): - return Error.parse_obj(obj) + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] - _obj = Error.parse_obj({"errors": obj.get("errors")}) - return _obj + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/hls_skip.py b/jellyfish/_openapi_client/models/hls_skip.py index ce51cf2..8cae45a 100644 --- a/jellyfish/_openapi_client/models/hls_skip.py +++ b/jellyfish/_openapi_client/models/hls_skip.py @@ -1,32 +1,8 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import json -import pprint -import re # noqa: F401 -from aenum import Enum, no_arg +from enum import Enum class HlsSkip(str, Enum): - """ - Is delta manifest requested - """ - - """ - allowed enum values - """ - TRUE = "true" + YES = "YES" - @classmethod - def from_json(cls, json_str: str) -> HlsSkip: - """Create an instance of HlsSkip from a JSON string""" - return HlsSkip(json.loads(json_str)) + def __str__(self) -> str: + return str(self.value) diff --git a/jellyfish/_openapi_client/models/peer.py b/jellyfish/_openapi_client/models/peer.py index 3a8e8ac..1c3a4ab 100644 --- a/jellyfish/_openapi_client/models/peer.py +++ b/jellyfish/_openapi_client/models/peer.py @@ -1,69 +1,76 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +from ..models.peer_status import PeerStatus - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="Peer") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class Peer: + """Describes peer status + Attributes: + id (str): Assigned peer id Example: peer-1. + status (PeerStatus): Informs about the peer status Example: disconnected. + type (str): Peer type Example: webrtc. + """ -from pydantic import BaseModel, Field, StrictStr -from jellyfish._openapi_client.models.peer_status import PeerStatus - + id: str + status: PeerStatus + type: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + id = self.id + status = self.status.value + + type = self.type + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "status": status, + "type": type, + } + ) -class Peer(BaseModel): - """ - Describes peer status - """ + return field_dict - id: StrictStr = Field(..., description="Assigned peer id") - status: PeerStatus = Field(...) - type: StrictStr = Field(..., description="Peer type") - __properties = ["id", "status", "type"] + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + id = d.pop("id") - class Config: - """Pydantic configuration""" + status = PeerStatus(d.pop("status")) - allow_population_by_field_name = True - validate_assignment = True + type = d.pop("type") - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + peer = cls( + id=id, + status=status, + type=type, + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + peer.additional_properties = d + return peer - @classmethod - def from_json(cls, json_str: str) -> Peer: - """Create an instance of Peer from a JSON string""" - return cls.from_dict(json.loads(json_str)) + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - @classmethod - def from_dict(cls, obj: dict) -> Peer: - """Create an instance of Peer from a dict""" - if obj is None: - return None + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value - if not isinstance(obj, dict): - return Peer.parse_obj(obj) + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] - _obj = Peer.parse_obj( - {"id": obj.get("id"), "status": obj.get("status"), "type": obj.get("type")} - ) - return _obj + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/peer_details_response.py b/jellyfish/_openapi_client/models/peer_details_response.py index ec905a1..34863f3 100644 --- a/jellyfish/_openapi_client/models/peer_details_response.py +++ b/jellyfish/_openapi_client/models/peer_details_response.py @@ -1,76 +1,65 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.peer_details_response_data import PeerDetailsResponseData - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="PeerDetailsResponse") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class PeerDetailsResponse: + """Response containing peer details and their token -from pydantic import BaseModel, Field -from jellyfish._openapi_client.models.peer_details_response_data import ( - PeerDetailsResponseData, -) + Attributes: + data (PeerDetailsResponseData): + """ + data: "PeerDetailsResponseData" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class PeerDetailsResponse(BaseModel): - """ - Response containing peer details and their token - """ + def to_dict(self) -> Dict[str, Any]: + data = self.data.to_dict() - data: PeerDetailsResponseData = Field(...) - __properties = ["data"] + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) - class Config: - """Pydantic configuration""" + return field_dict - allow_population_by_field_name = True - validate_assignment = True + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.peer_details_response_data import PeerDetailsResponseData - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + d = src_dict.copy() + data = PeerDetailsResponseData.from_dict(d.pop("data")) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + peer_details_response = cls( + data=data, + ) - @classmethod - def from_json(cls, json_str: str) -> PeerDetailsResponse: - """Create an instance of PeerDetailsResponse from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of data - if self.data: - _dict["data"] = self.data.to_dict() - return _dict + peer_details_response.additional_properties = d + return peer_details_response - @classmethod - def from_dict(cls, obj: dict) -> PeerDetailsResponse: - """Create an instance of PeerDetailsResponse from a dict""" - if obj is None: - return None + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - if not isinstance(obj, dict): - return PeerDetailsResponse.parse_obj(obj) + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - _obj = PeerDetailsResponse.parse_obj( - { - "data": PeerDetailsResponseData.from_dict(obj.get("data")) - if obj.get("data") is not None - else None - } - ) - return _obj + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/peer_details_response_data.py b/jellyfish/_openapi_client/models/peer_details_response_data.py index 2923e15..58bb706 100644 --- a/jellyfish/_openapi_client/models/peer_details_response_data.py +++ b/jellyfish/_openapi_client/models/peer_details_response_data.py @@ -1,78 +1,72 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.peer import Peer - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="PeerDetailsResponseData") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - -from pydantic import BaseModel, Field, StrictStr -from jellyfish._openapi_client.models.peer import Peer - - -class PeerDetailsResponseData(BaseModel): +@_attrs_define +class PeerDetailsResponseData: """ - PeerDetailsResponseData + Attributes: + peer (Peer): Describes peer status + token (str): Token for authorizing websocket connection Example: 5cdac726-57a3-4ecb-b1d5-72a3d62ec242. """ - peer: Peer = Field(...) - token: StrictStr = Field( - ..., description="Token for authorizing websocket connection" - ) - __properties = ["peer", "token"] + peer: "Peer" + token: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) - class Config: - """Pydantic configuration""" + def to_dict(self) -> Dict[str, Any]: + peer = self.peer.to_dict() - allow_population_by_field_name = True - validate_assignment = True + token = self.token - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "peer": peer, + "token": token, + } + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + return field_dict @classmethod - def from_json(cls, json_str: str) -> PeerDetailsResponseData: - """Create an instance of PeerDetailsResponseData from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of peer - if self.peer: - _dict["peer"] = self.peer.to_dict() - return _dict + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.peer import Peer - @classmethod - def from_dict(cls, obj: dict) -> PeerDetailsResponseData: - """Create an instance of PeerDetailsResponseData from a dict""" - if obj is None: - return None + d = src_dict.copy() + peer = Peer.from_dict(d.pop("peer")) - if not isinstance(obj, dict): - return PeerDetailsResponseData.parse_obj(obj) + token = d.pop("token") - _obj = PeerDetailsResponseData.parse_obj( - { - "peer": Peer.from_dict(obj.get("peer")) - if obj.get("peer") is not None - else None, - "token": obj.get("token"), - } + peer_details_response_data = cls( + peer=peer, + token=token, ) - return _obj + + peer_details_response_data.additional_properties = d + return peer_details_response_data + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/peer_options.py b/jellyfish/_openapi_client/models/peer_options.py deleted file mode 100644 index 6f3caf2..0000000 --- a/jellyfish/_openapi_client/models/peer_options.py +++ /dev/null @@ -1,143 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -from __future__ import annotations -from inspect import getfullargspec -import json -import pprint -import re # noqa: F401 - -from typing import Any, List, Optional -from pydantic import BaseModel, Field, StrictStr, ValidationError, validator -from jellyfish._openapi_client.models.peer_options_web_rtc import PeerOptionsWebRTC -from typing import Union, Any, List, TYPE_CHECKING -from pydantic import StrictStr, Field - -PEEROPTIONS_ONE_OF_SCHEMAS = ["PeerOptionsWebRTC"] - - -class PeerOptions(BaseModel): - """ - Peer-specific options - """ - - # data type: PeerOptionsWebRTC - oneof_schema_1_validator: Optional[PeerOptionsWebRTC] = None - if TYPE_CHECKING: - actual_instance: Union[PeerOptionsWebRTC] - else: - actual_instance: Any - one_of_schemas: List[str] = Field(PEEROPTIONS_ONE_OF_SCHEMAS, const=True) - - class Config: - validate_assignment = True - - def __init__(self, *args, **kwargs): - if args: - if len(args) > 1: - raise ValueError( - "If a position argument is used, only 1 is allowed to set `actual_instance`" - ) - if kwargs: - raise ValueError( - "If a position argument is used, keyword arguments cannot be used." - ) - super().__init__(actual_instance=args[0]) - else: - super().__init__(**kwargs) - - @validator("actual_instance") - def actual_instance_must_validate_oneof(cls, v): - instance = PeerOptions.construct() - error_messages = [] - match = 0 - # validate data type: PeerOptionsWebRTC - if not isinstance(v, PeerOptionsWebRTC): - error_messages.append( - f"Error! Input type `{type(v)}` is not `PeerOptionsWebRTC`" - ) - else: - match += 1 - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when setting `actual_instance` in PeerOptions with oneOf schemas: PeerOptionsWebRTC. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when setting `actual_instance` in PeerOptions with oneOf schemas: PeerOptionsWebRTC. Details: " - + ", ".join(error_messages) - ) - else: - return v - - @classmethod - def from_dict(cls, obj: dict) -> PeerOptions: - return cls.from_json(json.dumps(obj)) - - @classmethod - def from_json(cls, json_str: str) -> PeerOptions: - """Returns the object represented by the json string""" - instance = PeerOptions.construct() - error_messages = [] - match = 0 - - # deserialize data into PeerOptionsWebRTC - try: - instance.actual_instance = PeerOptionsWebRTC.from_json(json_str) - match += 1 - except (ValidationError, ValueError) as e: - error_messages.append(str(e)) - - if match > 1: - # more than 1 match - raise ValueError( - "Multiple matches found when deserializing the JSON string into PeerOptions with oneOf schemas: PeerOptionsWebRTC. Details: " - + ", ".join(error_messages) - ) - elif match == 0: - # no match - raise ValueError( - "No match found when deserializing the JSON string into PeerOptions with oneOf schemas: PeerOptionsWebRTC. Details: " - + ", ".join(error_messages) - ) - else: - return instance - - def to_json(self) -> str: - """Returns the JSON representation of the actual instance""" - if self.actual_instance is None: - return "null" - - to_json = getattr(self.actual_instance, "to_json", None) - if callable(to_json): - return self.actual_instance.to_json() - else: - return json.dumps(self.actual_instance) - - def to_dict(self) -> dict: - """Returns the dict representation of the actual instance""" - if self.actual_instance is None: - return None - - to_dict = getattr(self.actual_instance, "to_dict", None) - if callable(to_dict): - return self.actual_instance.to_dict() - else: - # primitive type - return self.actual_instance - - def to_str(self) -> str: - """Returns the string representation of the actual instance""" - return pprint.pformat(self.dict()) diff --git a/jellyfish/_openapi_client/models/peer_options_web_rtc.py b/jellyfish/_openapi_client/models/peer_options_web_rtc.py index c58f889..c314b96 100644 --- a/jellyfish/_openapi_client/models/peer_options_web_rtc.py +++ b/jellyfish/_openapi_client/models/peer_options_web_rtc.py @@ -1,73 +1,59 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar, Union -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +from ..types import UNSET, Unset - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="PeerOptionsWebRTC") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class PeerOptionsWebRTC: + """Options specific to the WebRTC peer + Attributes: + enable_simulcast (Union[Unset, bool]): Enables the peer to use simulcast Default: True. + """ -from typing import Optional -from pydantic import BaseModel, Field, StrictBool + enable_simulcast: Union[Unset, bool] = True + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + def to_dict(self) -> Dict[str, Any]: + enable_simulcast = self.enable_simulcast -class PeerOptionsWebRTC(BaseModel): - """ - Options specific to the WebRTC peer - """ + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if enable_simulcast is not UNSET: + field_dict["enableSimulcast"] = enable_simulcast - enable_simulcast: Optional[StrictBool] = Field( - True, alias="enableSimulcast", description="Enables the peer to use simulcast" - ) - __properties = ["enableSimulcast"] + return field_dict - class Config: - """Pydantic configuration""" + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + enable_simulcast = d.pop("enableSimulcast", UNSET) - allow_population_by_field_name = True - validate_assignment = True + peer_options_web_rtc = cls( + enable_simulcast=enable_simulcast, + ) - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + peer_options_web_rtc.additional_properties = d + return peer_options_web_rtc - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - @classmethod - def from_json(cls, json_str: str) -> PeerOptionsWebRTC: - """Create an instance of PeerOptionsWebRTC from a JSON string""" - return cls.from_dict(json.loads(json_str)) + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value - @classmethod - def from_dict(cls, obj: dict) -> PeerOptionsWebRTC: - """Create an instance of PeerOptionsWebRTC from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return PeerOptionsWebRTC.parse_obj(obj) - - _obj = PeerOptionsWebRTC.parse_obj( - { - "enable_simulcast": obj.get("enableSimulcast") - if obj.get("enableSimulcast") is not None - else True - } - ) - return _obj + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/peer_status.py b/jellyfish/_openapi_client/models/peer_status.py index d43864f..c11f20c 100644 --- a/jellyfish/_openapi_client/models/peer_status.py +++ b/jellyfish/_openapi_client/models/peer_status.py @@ -1,33 +1,9 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import json -import pprint -import re # noqa: F401 -from aenum import Enum, no_arg +from enum import Enum class PeerStatus(str, Enum): - """ - Informs about the peer status - """ - - """ - allowed enum values - """ CONNECTED = "connected" DISCONNECTED = "disconnected" - @classmethod - def from_json(cls, json_str: str) -> PeerStatus: - """Create an instance of PeerStatus from a JSON string""" - return PeerStatus(json.loads(json_str)) + def __str__(self) -> str: + return str(self.value) diff --git a/jellyfish/_openapi_client/models/recording_list_response.py b/jellyfish/_openapi_client/models/recording_list_response.py index 1378b7e..b48dbf6 100644 --- a/jellyfish/_openapi_client/models/recording_list_response.py +++ b/jellyfish/_openapi_client/models/recording_list_response.py @@ -1,65 +1,59 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar, cast -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +T = TypeVar("T", bound="RecordingListResponse") - Do not edit the class manually. -""" # noqa: E501 +@_attrs_define +class RecordingListResponse: + """Response containing list of all recording -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from typing import List -from pydantic import BaseModel, Field, StrictStr, conlist + Attributes: + data (List[str]): + """ + data: List[str] + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class RecordingListResponse(BaseModel): - """ - Response containing list of all recording - """ + def to_dict(self) -> Dict[str, Any]: + data = self.data - data: conlist(StrictStr) = Field(...) - __properties = ["data"] + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) - class Config: - """Pydantic configuration""" + return field_dict - allow_population_by_field_name = True - validate_assignment = True + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + data = cast(List[str], d.pop("data")) - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + recording_list_response = cls( + data=data, + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + recording_list_response.additional_properties = d + return recording_list_response - @classmethod - def from_json(cls, json_str: str) -> RecordingListResponse: - """Create an instance of RecordingListResponse from a JSON string""" - return cls.from_dict(json.loads(json_str)) + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - @classmethod - def from_dict(cls, obj: dict) -> RecordingListResponse: - """Create an instance of RecordingListResponse from a dict""" - if obj is None: - return None + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value - if not isinstance(obj, dict): - return RecordingListResponse.parse_obj(obj) + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] - _obj = RecordingListResponse.parse_obj({"data": obj.get("data")}) - return _obj + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/room.py b/jellyfish/_openapi_client/models/room.py index 1f81b37..a960829 100644 --- a/jellyfish/_openapi_client/models/room.py +++ b/jellyfish/_openapi_client/models/room.py @@ -1,103 +1,152 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.component_file import ComponentFile + from ..models.component_hls import ComponentHLS + from ..models.component_rtsp import ComponentRTSP + from ..models.peer import Peer + from ..models.room_config import RoomConfig - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="Room") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class Room: + """Description of the room state -from typing import List -from pydantic import BaseModel, Field, StrictStr, conlist -from jellyfish._openapi_client.models.component import Component -from jellyfish._openapi_client.models.peer import Peer -from jellyfish._openapi_client.models.room_config import RoomConfig + Attributes: + components (List[Union['ComponentFile', 'ComponentHLS', 'ComponentRTSP']]): + config (RoomConfig): Room configuration + id (str): Room ID Example: room-1. + peers (List['Peer']): + """ + components: List[Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]] + config: "RoomConfig" + id: str + peers: List["Peer"] + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class Room(BaseModel): - """ - Description of the room state - """ + def to_dict(self) -> Dict[str, Any]: + from ..models.component_hls import ComponentHLS + from ..models.component_rtsp import ComponentRTSP - components: conlist(Component) = Field(...) - config: RoomConfig = Field(...) - id: StrictStr = Field(..., description="Room ID") - peers: conlist(Peer) = Field(...) - __properties = ["components", "config", "id", "peers"] + components = [] + for components_item_data in self.components: + components_item: Dict[str, Any] - class Config: - """Pydantic configuration""" + if isinstance(components_item_data, ComponentHLS): + components_item = components_item_data.to_dict() - allow_population_by_field_name = True - validate_assignment = True + elif isinstance(components_item_data, ComponentRTSP): + components_item = components_item_data.to_dict() - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + else: + components_item = components_item_data.to_dict() - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + components.append(components_item) - @classmethod - def from_json(cls, json_str: str) -> Room: - """Create an instance of Room from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of each item in components (list) - _items = [] - if self.components: - for _item in self.components: - if _item: - _items.append(_item.to_dict()) - _dict["components"] = _items - # override the default output from pydantic by calling `to_dict()` of config - if self.config: - _dict["config"] = self.config.to_dict() - # override the default output from pydantic by calling `to_dict()` of each item in peers (list) - _items = [] - if self.peers: - for _item in self.peers: - if _item: - _items.append(_item.to_dict()) - _dict["peers"] = _items - return _dict + config = self.config.to_dict() - @classmethod - def from_dict(cls, obj: dict) -> Room: - """Create an instance of Room from a dict""" - if obj is None: - return None + id = self.id + peers = [] + for peers_item_data in self.peers: + peers_item = peers_item_data.to_dict() - if not isinstance(obj, dict): - return Room.parse_obj(obj) + peers.append(peers_item) - _obj = Room.parse_obj( + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( { - "components": [ - Component.from_dict(_item) for _item in obj.get("components") - ] - if obj.get("components") is not None - else None, - "config": RoomConfig.from_dict(obj.get("config")) - if obj.get("config") is not None - else None, - "id": obj.get("id"), - "peers": [Peer.from_dict(_item) for _item in obj.get("peers")] - if obj.get("peers") is not None - else None, + "components": components, + "config": config, + "id": id, + "peers": peers, } ) - return _obj + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.component_file import ComponentFile + from ..models.component_hls import ComponentHLS + from ..models.component_rtsp import ComponentRTSP + from ..models.peer import Peer + from ..models.room_config import RoomConfig + + d = src_dict.copy() + components = [] + _components = d.pop("components") + for components_item_data in _components: + + def _parse_components_item( + data: object, + ) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_0 = ComponentHLS.from_dict(data) + + return componentsschemas_component_type_0 + except: # noqa: E722 + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_1 = ComponentRTSP.from_dict(data) + + return componentsschemas_component_type_1 + except: # noqa: E722 + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_component_type_2 = ComponentFile.from_dict(data) + + return componentsschemas_component_type_2 + + components_item = _parse_components_item(components_item_data) + + components.append(components_item) + + config = RoomConfig.from_dict(d.pop("config")) + + id = d.pop("id") + + peers = [] + _peers = d.pop("peers") + for peers_item_data in _peers: + peers_item = Peer.from_dict(peers_item_data) + + peers.append(peers_item) + + room = cls( + components=components, + config=config, + id=id, + peers=peers, + ) + + room.additional_properties = d + return room + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/room_config.py b/jellyfish/_openapi_client/models/room_config.py index d17ba5a..dd4b7d7 100644 --- a/jellyfish/_openapi_client/models/room_config.py +++ b/jellyfish/_openapi_client/models/room_config.py @@ -1,110 +1,87 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar, Union -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +from ..models.room_config_video_codec import RoomConfigVideoCodec +from ..types import UNSET, Unset - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="RoomConfig") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class RoomConfig: + """Room configuration + Attributes: + max_peers (Union[Unset, None, int]): Maximum amount of peers allowed into the room Example: 10. + video_codec (Union[Unset, None, RoomConfigVideoCodec]): Enforces video codec for each peer in the room + webhook_url (Union[Unset, None, str]): URL where Jellyfish notifications will be sent Example: + https://backend.address.com/jellyfish-notifications-endpoint. + """ -from typing import Optional -from pydantic import BaseModel, Field, StrictStr, conint, validator + max_peers: Union[Unset, None, int] = UNSET + video_codec: Union[Unset, None, RoomConfigVideoCodec] = UNSET + webhook_url: Union[Unset, None, str] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + def to_dict(self) -> Dict[str, Any]: + max_peers = self.max_peers + video_codec: Union[Unset, None, str] = UNSET + if not isinstance(self.video_codec, Unset): + video_codec = self.video_codec.value if self.video_codec else None -class RoomConfig(BaseModel): - """ - Room configuration - """ + webhook_url = self.webhook_url - max_peers: Optional[conint(strict=True, ge=1)] = Field( - None, - alias="maxPeers", - description="Maximum amount of peers allowed into the room", - ) - video_codec: Optional[StrictStr] = Field( - None, - alias="videoCodec", - description="Enforces video codec for each peer in the room", - ) - webhook_url: Optional[StrictStr] = Field( - None, - alias="webhookUrl", - description="URL where Jellyfish notifications will be sent", - ) - __properties = ["maxPeers", "videoCodec", "webhookUrl"] - - @validator("video_codec") - def video_codec_validate_enum(cls, value): - """Validates the enum""" - if value is None: - return value - - if value not in ("h264", "vp8"): - raise ValueError("must be one of enum values ('h264', 'vp8')") - return value - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if max_peers is not UNSET: + field_dict["maxPeers"] = max_peers + if video_codec is not UNSET: + field_dict["videoCodec"] = video_codec + if webhook_url is not UNSET: + field_dict["webhookUrl"] = webhook_url - @classmethod - def from_json(cls, json_str: str) -> RoomConfig: - """Create an instance of RoomConfig from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # set to None if max_peers (nullable) is None - # and __fields_set__ contains the field - if self.max_peers is None and "max_peers" in self.__fields_set__: - _dict["maxPeers"] = None - - # set to None if video_codec (nullable) is None - # and __fields_set__ contains the field - if self.video_codec is None and "video_codec" in self.__fields_set__: - _dict["videoCodec"] = None - - # set to None if webhook_url (nullable) is None - # and __fields_set__ contains the field - if self.webhook_url is None and "webhook_url" in self.__fields_set__: - _dict["webhookUrl"] = None - - return _dict + return field_dict @classmethod - def from_dict(cls, obj: dict) -> RoomConfig: - """Create an instance of RoomConfig from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return RoomConfig.parse_obj(obj) - - _obj = RoomConfig.parse_obj( - { - "max_peers": obj.get("maxPeers"), - "video_codec": obj.get("videoCodec"), - "webhook_url": obj.get("webhookUrl"), - } + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + max_peers = d.pop("maxPeers", UNSET) + + _video_codec = d.pop("videoCodec", UNSET) + video_codec: Union[Unset, None, RoomConfigVideoCodec] + if _video_codec is None: + video_codec = None + elif isinstance(_video_codec, Unset): + video_codec = UNSET + else: + video_codec = RoomConfigVideoCodec(_video_codec) + + webhook_url = d.pop("webhookUrl", UNSET) + + room_config = cls( + max_peers=max_peers, + video_codec=video_codec, + webhook_url=webhook_url, ) - return _obj + + room_config.additional_properties = d + return room_config + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/room_config_video_codec.py b/jellyfish/_openapi_client/models/room_config_video_codec.py new file mode 100644 index 0000000..470fa4d --- /dev/null +++ b/jellyfish/_openapi_client/models/room_config_video_codec.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class RoomConfigVideoCodec(str, Enum): + H264 = "h264" + VP8 = "vp8" + + def __str__(self) -> str: + return str(self.value) diff --git a/jellyfish/_openapi_client/models/room_create_details_response.py b/jellyfish/_openapi_client/models/room_create_details_response.py index d31ac50..5573ee2 100644 --- a/jellyfish/_openapi_client/models/room_create_details_response.py +++ b/jellyfish/_openapi_client/models/room_create_details_response.py @@ -1,76 +1,67 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.room_create_details_response_data import RoomCreateDetailsResponseData - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="RoomCreateDetailsResponse") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class RoomCreateDetailsResponse: + """Response containing room details -from pydantic import BaseModel, Field -from jellyfish._openapi_client.models.room_create_details_response_data import ( - RoomCreateDetailsResponseData, -) + Attributes: + data (RoomCreateDetailsResponseData): + """ + data: "RoomCreateDetailsResponseData" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class RoomCreateDetailsResponse(BaseModel): - """ - Response containing room details - """ + def to_dict(self) -> Dict[str, Any]: + data = self.data.to_dict() + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) + + return field_dict - data: RoomCreateDetailsResponseData = Field(...) - __properties = ["data"] + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.room_create_details_response_data import ( + RoomCreateDetailsResponseData, + ) - class Config: - """Pydantic configuration""" + d = src_dict.copy() + data = RoomCreateDetailsResponseData.from_dict(d.pop("data")) - allow_population_by_field_name = True - validate_assignment = True + room_create_details_response = cls( + data=data, + ) - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + room_create_details_response.additional_properties = d + return room_create_details_response - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - @classmethod - def from_json(cls, json_str: str) -> RoomCreateDetailsResponse: - """Create an instance of RoomCreateDetailsResponse from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of data - if self.data: - _dict["data"] = self.data.to_dict() - return _dict + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - @classmethod - def from_dict(cls, obj: dict) -> RoomCreateDetailsResponse: - """Create an instance of RoomCreateDetailsResponse from a dict""" - if obj is None: - return None + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value - if not isinstance(obj, dict): - return RoomCreateDetailsResponse.parse_obj(obj) + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] - _obj = RoomCreateDetailsResponse.parse_obj( - { - "data": RoomCreateDetailsResponseData.from_dict(obj.get("data")) - if obj.get("data") is not None - else None - } - ) - return _obj + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/room_create_details_response_data.py b/jellyfish/_openapi_client/models/room_create_details_response_data.py index 3c886fc..726f8ab 100644 --- a/jellyfish/_openapi_client/models/room_create_details_response_data.py +++ b/jellyfish/_openapi_client/models/room_create_details_response_data.py @@ -1,79 +1,73 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.room import Room - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="RoomCreateDetailsResponseData") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - -from pydantic import BaseModel, Field, StrictStr -from jellyfish._openapi_client.models.room import Room - - -class RoomCreateDetailsResponseData(BaseModel): +@_attrs_define +class RoomCreateDetailsResponseData: """ - RoomCreateDetailsResponseData + Attributes: + jellyfish_address (str): Jellyfish instance address where the room was created. This might be different than the + address of Jellyfish where the request was sent only when running a cluster of Jellyfishes. Example: + jellyfish1:5003. + room (Room): Description of the room state """ - jellyfish_address: StrictStr = Field( - ..., - description="Jellyfish instance address where the room was created. This might be different than the address of Jellyfish where the request was sent only when running a cluster of Jellyfishes.", - ) - room: Room = Field(...) - __properties = ["jellyfish_address", "room"] - - class Config: - """Pydantic configuration""" + jellyfish_address: str + room: "Room" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) - allow_population_by_field_name = True - validate_assignment = True + def to_dict(self) -> Dict[str, Any]: + jellyfish_address = self.jellyfish_address + room = self.room.to_dict() - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "jellyfish_address": jellyfish_address, + "room": room, + } + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + return field_dict @classmethod - def from_json(cls, json_str: str) -> RoomCreateDetailsResponseData: - """Create an instance of RoomCreateDetailsResponseData from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of room - if self.room: - _dict["room"] = self.room.to_dict() - return _dict + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.room import Room - @classmethod - def from_dict(cls, obj: dict) -> RoomCreateDetailsResponseData: - """Create an instance of RoomCreateDetailsResponseData from a dict""" - if obj is None: - return None + d = src_dict.copy() + jellyfish_address = d.pop("jellyfish_address") - if not isinstance(obj, dict): - return RoomCreateDetailsResponseData.parse_obj(obj) + room = Room.from_dict(d.pop("room")) - _obj = RoomCreateDetailsResponseData.parse_obj( - { - "jellyfish_address": obj.get("jellyfish_address"), - "room": Room.from_dict(obj.get("room")) - if obj.get("room") is not None - else None, - } + room_create_details_response_data = cls( + jellyfish_address=jellyfish_address, + room=room, ) - return _obj + + room_create_details_response_data.additional_properties = d + return room_create_details_response_data + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/room_details_response.py b/jellyfish/_openapi_client/models/room_details_response.py index 85c4135..1bc222b 100644 --- a/jellyfish/_openapi_client/models/room_details_response.py +++ b/jellyfish/_openapi_client/models/room_details_response.py @@ -1,74 +1,65 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.room import Room - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="RoomDetailsResponse") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class RoomDetailsResponse: + """Response containing room details -from pydantic import BaseModel, Field -from jellyfish._openapi_client.models.room import Room + Attributes: + data (Room): Description of the room state + """ + data: "Room" + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class RoomDetailsResponse(BaseModel): - """ - Response containing room details - """ + def to_dict(self) -> Dict[str, Any]: + data = self.data.to_dict() - data: Room = Field(...) - __properties = ["data"] + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) - class Config: - """Pydantic configuration""" + return field_dict - allow_population_by_field_name = True - validate_assignment = True + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.room import Room - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + d = src_dict.copy() + data = Room.from_dict(d.pop("data")) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + room_details_response = cls( + data=data, + ) - @classmethod - def from_json(cls, json_str: str) -> RoomDetailsResponse: - """Create an instance of RoomDetailsResponse from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of data - if self.data: - _dict["data"] = self.data.to_dict() - return _dict + room_details_response.additional_properties = d + return room_details_response - @classmethod - def from_dict(cls, obj: dict) -> RoomDetailsResponse: - """Create an instance of RoomDetailsResponse from a dict""" - if obj is None: - return None + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - if not isinstance(obj, dict): - return RoomDetailsResponse.parse_obj(obj) + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - _obj = RoomDetailsResponse.parse_obj( - { - "data": Room.from_dict(obj.get("data")) - if obj.get("data") is not None - else None - } - ) - return _obj + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/rooms_listing_response.py b/jellyfish/_openapi_client/models/rooms_listing_response.py index 4467c10..30ed582 100644 --- a/jellyfish/_openapi_client/models/rooms_listing_response.py +++ b/jellyfish/_openapi_client/models/rooms_listing_response.py @@ -1,79 +1,74 @@ -# coding: utf-8 +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +if TYPE_CHECKING: + from ..models.room import Room - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="RoomsListingResponse") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class RoomsListingResponse: + """Response containing list of all rooms -from typing import List -from pydantic import BaseModel, Field, conlist -from jellyfish._openapi_client.models.room import Room - - -class RoomsListingResponse(BaseModel): - """ - Response containing list of all rooms + Attributes: + data (List['Room']): """ - data: conlist(Room) = Field(...) - __properties = ["data"] + data: List["Room"] + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) - class Config: - """Pydantic configuration""" + def to_dict(self) -> Dict[str, Any]: + data = [] + for data_item_data in self.data: + data_item = data_item_data.to_dict() - allow_population_by_field_name = True - validate_assignment = True + data.append(data_item) - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + } + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + return field_dict @classmethod - def from_json(cls, json_str: str) -> RoomsListingResponse: - """Create an instance of RoomsListingResponse from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - # override the default output from pydantic by calling `to_dict()` of each item in data (list) - _items = [] - if self.data: - for _item in self.data: - if _item: - _items.append(_item.to_dict()) - _dict["data"] = _items - return _dict + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.room import Room - @classmethod - def from_dict(cls, obj: dict) -> RoomsListingResponse: - """Create an instance of RoomsListingResponse from a dict""" - if obj is None: - return None + d = src_dict.copy() + data = [] + _data = d.pop("data") + for data_item_data in _data: + data_item = Room.from_dict(data_item_data) - if not isinstance(obj, dict): - return RoomsListingResponse.parse_obj(obj) + data.append(data_item) - _obj = RoomsListingResponse.parse_obj( - { - "data": [Room.from_dict(_item) for _item in obj.get("data")] - if obj.get("data") is not None - else None - } + rooms_listing_response = cls( + data=data, ) - return _obj + + rooms_listing_response.additional_properties = d + return rooms_listing_response + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/s3_credentials.py b/jellyfish/_openapi_client/models/s3_credentials.py index 55ff77a..8115093 100644 --- a/jellyfish/_openapi_client/models/s3_credentials.py +++ b/jellyfish/_openapi_client/models/s3_credentials.py @@ -1,86 +1,81 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +T = TypeVar("T", bound="S3Credentials") - Do not edit the class manually. -""" # noqa: E501 +@_attrs_define +class S3Credentials: + """An AWS S3 credential that will be used to send HLS stream. The stream will only be uploaded if credentials are + provided -from __future__ import annotations -import pprint -import re # noqa: F401 -import json + Attributes: + access_key_id (str): An AWS access key identifier, linked to your AWS account. + bucket (str): The name of the S3 bucket where your data will be stored. + region (str): The AWS region where your bucket is located. + secret_access_key (str): The secret key that is linked to the Access Key ID. + """ + access_key_id: str + bucket: str + region: str + secret_access_key: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + access_key_id = self.access_key_id + bucket = self.bucket + region = self.region + secret_access_key = self.secret_access_key + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "accessKeyId": access_key_id, + "bucket": bucket, + "region": region, + "secretAccessKey": secret_access_key, + } + ) -from pydantic import BaseModel, Field, StrictStr + return field_dict + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + access_key_id = d.pop("accessKeyId") -class S3Credentials(BaseModel): - """ - An AWS S3 credential that will be used to send HLS stream. The stream will only be uploaded if credentials are provided - """ + bucket = d.pop("bucket") - access_key_id: StrictStr = Field( - ..., - alias="accessKeyId", - description="An AWS access key identifier, linked to your AWS account.", - ) - bucket: StrictStr = Field( - ..., description="The name of the S3 bucket where your data will be stored." - ) - region: StrictStr = Field( - ..., description="The AWS region where your bucket is located." - ) - secret_access_key: StrictStr = Field( - ..., - alias="secretAccessKey", - description="The secret key that is linked to the Access Key ID.", - ) - __properties = ["accessKeyId", "bucket", "region", "secretAccessKey"] - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + region = d.pop("region") - @classmethod - def from_json(cls, json_str: str) -> S3Credentials: - """Create an instance of S3Credentials from a JSON string""" - return cls.from_dict(json.loads(json_str)) + secret_access_key = d.pop("secretAccessKey") - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + s3_credentials = cls( + access_key_id=access_key_id, + bucket=bucket, + region=region, + secret_access_key=secret_access_key, + ) - @classmethod - def from_dict(cls, obj: dict) -> S3Credentials: - """Create an instance of S3Credentials from a dict""" - if obj is None: - return None + s3_credentials.additional_properties = d + return s3_credentials - if not isinstance(obj, dict): - return S3Credentials.parse_obj(obj) + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - _obj = S3Credentials.parse_obj( - { - "access_key_id": obj.get("accessKeyId"), - "bucket": obj.get("bucket"), - "region": obj.get("region"), - "secret_access_key": obj.get("secretAccessKey"), - } - ) - return _obj + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/models/subscription_config.py b/jellyfish/_openapi_client/models/subscription_config.py index 8c2fe76..2b04727 100644 --- a/jellyfish/_openapi_client/models/subscription_config.py +++ b/jellyfish/_openapi_client/models/subscription_config.py @@ -1,67 +1,61 @@ -# coding: utf-8 +from typing import Any, Dict, List, Type, TypeVar, Union, cast -""" - Python API wrapper for Jellyfish Media Server +from attrs import define as _attrs_define +from attrs import field as _attrs_field - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) +from ..types import UNSET, Unset - Do not edit the class manually. -""" # noqa: E501 +T = TypeVar("T", bound="SubscriptionConfig") -from __future__ import annotations -import pprint -import re # noqa: F401 -import json +@_attrs_define +class SubscriptionConfig: + """Subscription config + Attributes: + tracks (Union[Unset, List[str]]): List of tracks that hls endpoint will subscribe for + """ -from typing import List, Optional -from pydantic import BaseModel, Field, StrictStr, conlist - + tracks: Union[Unset, List[str]] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) -class SubscriptionConfig(BaseModel): - """ - Subscription config - """ + def to_dict(self) -> Dict[str, Any]: + tracks: Union[Unset, List[str]] = UNSET + if not isinstance(self.tracks, Unset): + tracks = self.tracks - tracks: Optional[conlist(StrictStr)] = Field( - None, description="List of tracks that hls endpoint will subscribe for" - ) - __properties = ["tracks"] + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if tracks is not UNSET: + field_dict["tracks"] = tracks - class Config: - """Pydantic configuration""" + return field_dict - allow_population_by_field_name = True - validate_assignment = True + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + tracks = cast(List[str], d.pop("tracks", UNSET)) - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) + subscription_config = cls( + tracks=tracks, + ) - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - return json.dumps(self.to_dict()) + subscription_config.additional_properties = d + return subscription_config - @classmethod - def from_json(cls, json_str: str) -> SubscriptionConfig: - """Create an instance of SubscriptionConfig from a JSON string""" - return cls.from_dict(json.loads(json_str)) + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) - def to_dict(self): - """Returns the dictionary representation of the model using alias""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] - @classmethod - def from_dict(cls, obj: dict) -> SubscriptionConfig: - """Create an instance of SubscriptionConfig from a dict""" - if obj is None: - return None + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value - if not isinstance(obj, dict): - return SubscriptionConfig.parse_obj(obj) + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] - _obj = SubscriptionConfig.parse_obj({"tracks": obj.get("tracks")}) - return _obj + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/jellyfish/_openapi_client/py.typed b/jellyfish/_openapi_client/py.typed index e69de29..1aad327 100644 --- a/jellyfish/_openapi_client/py.typed +++ b/jellyfish/_openapi_client/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 \ No newline at end of file diff --git a/jellyfish/_openapi_client/rest.py b/jellyfish/_openapi_client/rest.py deleted file mode 100644 index fbd7734..0000000 --- a/jellyfish/_openapi_client/rest.py +++ /dev/null @@ -1,401 +0,0 @@ -# coding: utf-8 - -""" - Python API wrapper for Jellyfish Media Server - - The version of the OpenAPI document: 0.2.0 - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 - - -import io -import json -import logging -import re -import ssl - -from urllib.parse import urlencode, quote_plus -import urllib3 - -from jellyfish._openapi_client.exceptions import ( - ApiException, - UnauthorizedException, - ForbiddenException, - NotFoundException, - ServiceException, - ApiValueError, - BadRequestException, -) - - -logger = logging.getLogger(__name__) - - -class RESTResponse(io.IOBase): - def __init__(self, resp): - self.urllib3_response = resp - self.status = resp.status - self.reason = resp.reason - self.data = resp.data - - def getheaders(self): - """Returns a dictionary of the response headers.""" - return self.urllib3_response.headers - - def getheader(self, name, default=None): - """Returns a given response header.""" - return self.urllib3_response.headers.get(name, default) - - -class RESTClientObject(object): - def __init__(self, configuration, pools_size=4, maxsize=None): - # urllib3.PoolManager will pass all kw parameters to connectionpool - # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501 - # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501 - # maxsize is the number of requests to host that are allowed in parallel # noqa: E501 - # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501 - - # cert_reqs - if configuration.verify_ssl: - cert_reqs = ssl.CERT_REQUIRED - else: - cert_reqs = ssl.CERT_NONE - - addition_pool_args = {} - if configuration.assert_hostname is not None: - addition_pool_args[ - "assert_hostname" - ] = configuration.assert_hostname # noqa: E501 - - if configuration.retries is not None: - addition_pool_args["retries"] = configuration.retries - - if configuration.tls_server_name: - addition_pool_args["server_hostname"] = configuration.tls_server_name - - if configuration.socket_options is not None: - addition_pool_args["socket_options"] = configuration.socket_options - - if maxsize is None: - if configuration.connection_pool_maxsize is not None: - maxsize = configuration.connection_pool_maxsize - else: - maxsize = 4 - - # https pool manager - if configuration.proxy: - self.pool_manager = urllib3.ProxyManager( - num_pools=pools_size, - maxsize=maxsize, - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - proxy_headers=configuration.proxy_headers, - **addition_pool_args - ) - else: - self.pool_manager = urllib3.PoolManager( - num_pools=pools_size, - maxsize=maxsize, - cert_reqs=cert_reqs, - ca_certs=configuration.ssl_ca_cert, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) - - def request( - self, - method, - url, - query_params=None, - headers=None, - body=None, - post_params=None, - _preload_content=True, - _request_timeout=None, - ): - """Perform requests. - - :param method: http request method - :param url: http request url - :param query_params: query parameters in the url - :param headers: http request headers - :param body: request json body, for `application/json` - :param post_params: request post parameters, - `application/x-www-form-urlencoded` - and `multipart/form-data` - :param _preload_content: if False, the urllib3.HTTPResponse object will - be returned without reading/decoding response - data. Default is True. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - """ - method = method.upper() - assert method in ["GET", "HEAD", "DELETE", "POST", "PUT", "PATCH", "OPTIONS"] - - if post_params and body: - raise ApiValueError( - "body parameter cannot be used with post_params parameter." - ) - - post_params = post_params or {} - headers = headers or {} - # url already contains the URL query string - # so reset query_params to empty dict - query_params = {} - - timeout = None - if _request_timeout: - if isinstance(_request_timeout, (int, float)): # noqa: E501,F821 - timeout = urllib3.Timeout(total=_request_timeout) - elif isinstance(_request_timeout, tuple) and len(_request_timeout) == 2: - timeout = urllib3.Timeout( - connect=_request_timeout[0], read=_request_timeout[1] - ) - - try: - # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` - if method in ["POST", "PUT", "PATCH", "OPTIONS", "DELETE"]: - # no content type provided or payload is json - if not headers.get("Content-Type") or re.search( - "json", headers["Content-Type"], re.IGNORECASE - ): - request_body = None - if body is not None: - request_body = json.dumps(body) - r = self.pool_manager.request( - method, - url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers, - ) - elif ( - headers["Content-Type"] == "application/x-www-form-urlencoded" - ): # noqa: E501 - r = self.pool_manager.request( - method, - url, - fields=post_params, - encode_multipart=False, - preload_content=_preload_content, - timeout=timeout, - headers=headers, - ) - elif headers["Content-Type"] == "multipart/form-data": - # must del headers['Content-Type'], or the correct - # Content-Type which generated by urllib3 will be - # overwritten. - del headers["Content-Type"] - r = self.pool_manager.request( - method, - url, - fields=post_params, - encode_multipart=True, - preload_content=_preload_content, - timeout=timeout, - headers=headers, - ) - # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form - elif isinstance(body, str) or isinstance(body, bytes): - request_body = body - r = self.pool_manager.request( - method, - url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers, - ) - else: - # Cannot generate the request from given parameters - msg = """Cannot prepare a request message for provided - arguments. Please check that your arguments match - declared content type.""" - raise ApiException(status=0, reason=msg) - # For `GET`, `HEAD` - else: - r = self.pool_manager.request( - method, - url, - fields={}, - preload_content=_preload_content, - timeout=timeout, - headers=headers, - ) - except urllib3.exceptions.SSLError as e: - msg = "{0}\n{1}".format(type(e).__name__, str(e)) - raise ApiException(status=0, reason=msg) - - if _preload_content: - r = RESTResponse(r) - - # log response body - logger.debug("response body: %s", r.data) - - if not 200 <= r.status <= 299: - if r.status == 400: - raise BadRequestException(http_resp=r) - - if r.status == 401: - raise UnauthorizedException(http_resp=r) - - if r.status == 403: - raise ForbiddenException(http_resp=r) - - if r.status == 404: - raise NotFoundException(http_resp=r) - - if 500 <= r.status <= 599: - raise ServiceException(http_resp=r) - - raise ApiException(http_resp=r) - - return r - - def get_request( - self, - url, - headers=None, - query_params=None, - _preload_content=True, - _request_timeout=None, - ): - return self.request( - "GET", - url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params, - ) - - def head_request( - self, - url, - headers=None, - query_params=None, - _preload_content=True, - _request_timeout=None, - ): - return self.request( - "HEAD", - url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params, - ) - - def options_request( - self, - url, - headers=None, - query_params=None, - post_params=None, - body=None, - _preload_content=True, - _request_timeout=None, - ): - return self.request( - "OPTIONS", - url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - - def delete_request( - self, - url, - headers=None, - query_params=None, - body=None, - _preload_content=True, - _request_timeout=None, - ): - return self.request( - "DELETE", - url, - headers=headers, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - - def post_request( - self, - url, - headers=None, - query_params=None, - post_params=None, - body=None, - _preload_content=True, - _request_timeout=None, - ): - return self.request( - "POST", - url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - - def put_request( - self, - url, - headers=None, - query_params=None, - post_params=None, - body=None, - _preload_content=True, - _request_timeout=None, - ): - return self.request( - "PUT", - url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) - - def patch_request( - self, - url, - headers=None, - query_params=None, - post_params=None, - body=None, - _preload_content=True, - _request_timeout=None, - ): - return self.request( - "PATCH", - url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body, - ) diff --git a/jellyfish/_openapi_client/types.py b/jellyfish/_openapi_client/types.py new file mode 100644 index 0000000..15700b8 --- /dev/null +++ b/jellyfish/_openapi_client/types.py @@ -0,0 +1,44 @@ +""" Contains some shared types for properties """ +from http import HTTPStatus +from typing import BinaryIO, Generic, Literal, MutableMapping, Optional, Tuple, TypeVar + +from attrs import define + + +class Unset: + def __bool__(self) -> Literal[False]: + return False + + +UNSET: Unset = Unset() + +FileJsonType = Tuple[Optional[str], BinaryIO, Optional[str]] + + +@define +class File: + """Contains information for file uploads""" + + payload: BinaryIO + file_name: Optional[str] = None + mime_type: Optional[str] = None + + def to_tuple(self) -> FileJsonType: + """Return a tuple representation that httpx will accept for multipart/form-data""" + return self.file_name, self.payload, self.mime_type + + +T = TypeVar("T") + + +@define +class Response(Generic[T]): + """A response from an endpoint""" + + status_code: HTTPStatus + content: bytes + headers: MutableMapping[str, str] + parsed: Optional[T] + + +__all__ = ["File", "Response", "FileJsonType"] diff --git a/jellyfish/_recording_api.py b/jellyfish/_recording_api.py index b6fbe0d..1fa123a 100644 --- a/jellyfish/_recording_api.py +++ b/jellyfish/_recording_api.py @@ -2,7 +2,9 @@ RecordingApi used to manage rooms """ -from jellyfish import _openapi_client as jellyfish_api +from jellyfish._openapi_client import AuthenticatedClient +from jellyfish._openapi_client.api.recording import get_recordings, delete_recording +from jellyfish._openapi_client.models import Error class RecordingApi: @@ -20,19 +22,23 @@ def __init__( """ protocol = "https" if secure else "http" - self._configuration = jellyfish_api.Configuration( - host=f"{protocol}://{server_address}", access_token=server_api_token + self._client = AuthenticatedClient( + f"{protocol}://{server_address}", token=server_api_token ) - self._api_client = jellyfish_api.ApiClient(self._configuration) - self._recording_api = jellyfish_api.RecordingApi(self._api_client) - def get_list(self) -> list: """Returns a list of available recordings""" - return self._recording_api.get_recordings().data + return self._request(get_recordings).data def delete(self, recording_id: str): """Deletes recording with given id""" - return self._recording_api.delete_recording(recording_id) + return self._request(delete_recording, recording_id=recording_id) + + def _request(self, method, **kwargs): + resp = method.sync(client=self._client, **kwargs) + if isinstance(resp, Error): + raise RuntimeError(resp.errors) + + return resp diff --git a/jellyfish/_room_api.py b/jellyfish/_room_api.py index 81691bd..c94e63e 100644 --- a/jellyfish/_room_api.py +++ b/jellyfish/_room_api.py @@ -2,22 +2,34 @@ RoomApi used to manage rooms """ -from typing import Union, Literal +from typing import Literal, Union + +from jellyfish._openapi_client import AuthenticatedClient +from jellyfish._openapi_client.api.room import ( + add_component, + add_peer, + create_room, + delete_component, + delete_peer, + delete_room, + get_all_rooms, + get_room, +) -from jellyfish import _openapi_client as jellyfish_api +from jellyfish._openapi_client.api.hls import subscribe_tracks -from jellyfish._openapi_client import ( - AddPeerRequest, - AddComponentRequest, - PeerOptions, - PeerOptionsWebRTC, - Component, - ComponentOptions, - ComponentOptionsHLS, - ComponentOptionsRTSP, +from jellyfish._openapi_client.models import ( + AddPeerJsonBody, + AddComponentJsonBody, + SubscriptionConfig, Room, + PeerOptionsWebRTC, RoomConfig, Peer, + ComponentOptionsHLS, + ComponentOptionsRTSP, + RoomConfigVideoCodec, + Error, ) @@ -36,13 +48,10 @@ def __init__( """ protocol = "https" if secure else "http" - self._configuration = jellyfish_api.Configuration( - host=f"{protocol}://{server_address}", access_token=server_api_token - ) - self._api_client = jellyfish_api.ApiClient(self._configuration) - self._room_api = jellyfish_api.RoomApi(self._api_client) - self._hls_api = jellyfish_api.HlsApi(self._api_client) + self._client = AuthenticatedClient( + f"{protocol}://{server_address}", token=server_api_token + ) def create_room( self, @@ -60,27 +69,33 @@ def create_room( In such case, a new `RoomApi` instance has to be created using the returned address in order to interact with the room. """ + + if video_codec is not None: + video_codec = RoomConfigVideoCodec(video_codec) + else: + video_codec = None + room_config = RoomConfig( - maxPeers=max_peers, videoCodec=video_codec, webhook_url=webhook_url + max_peers=max_peers, video_codec=video_codec, webhook_url=webhook_url ) - resp = self._room_api.create_room(room_config) + resp = self._request(create_room, json_body=room_config) return (resp.data.jellyfish_address, resp.data.room) def delete_room(self, room_id: str) -> None: """Deletes a room""" - return self._room_api.delete_room(room_id) + return self._request(delete_room, room_id=room_id) def get_all_rooms(self) -> list: """Returns list of all rooms""" - return self._room_api.get_all_rooms().data + return self._request(get_all_rooms).data def get_room(self, room_id: str) -> Room: """Returns room with the given id""" - return self._room_api.get_room(room_id).data + return self._request(get_room, room_id=room_id).data def add_peer(self, room_id: str, options: PeerOptionsWebRTC) -> (str, Peer): """ @@ -93,20 +108,19 @@ def add_peer(self, room_id: str, options: PeerOptionsWebRTC) -> (str, Peer): """ peer_type = "webrtc" - options = PeerOptions(options) - request = AddPeerRequest(type=peer_type, options=options) + json_body = AddPeerJsonBody(type=peer_type, options=options) - resp = self._room_api.add_peer(room_id, request) + resp = self._request(add_peer, room_id=room_id, json_body=json_body) return (resp.data.token, resp.data.peer) def delete_peer(self, room_id: str, peer_id: str) -> None: """Deletes peer""" - return self._room_api.delete_peer(room_id, peer_id) + return self._request(delete_peer, id=peer_id, room_id=room_id) def add_component( self, room_id: str, options: Union[ComponentOptionsHLS, ComponentOptionsRTSP] - ) -> Component: + ) -> any: """Creates component in the room""" if isinstance(options, ComponentOptionsHLS): @@ -118,17 +132,27 @@ def add_component( "options must be either ComponentOptionsHLS or ComponentOptionsRTSP" ) - options = ComponentOptions(options) - request = AddComponentRequest(type=component_type, options=options) + json_body = AddComponentJsonBody(type=component_type, options=options) - return self._room_api.add_component(room_id, request).data + return self._request(add_component, room_id=room_id, json_body=json_body).data def delete_component(self, room_id: str, component_id: str) -> None: """Deletes component""" - return self._room_api.delete_component(room_id, component_id) + return self._request(delete_component, id=component_id, room_id=room_id) def hls_subscribe(self, room_id: str, tracks: list): """subscribes hls component for tracks""" - return self._hls_api.subscribe_tracks(room_id, {"tracks": tracks}) + subscription_config = SubscriptionConfig(tracks=tracks) + + return self._request( + subscribe_tracks, room_id=room_id, json_body=subscription_config + ) + + def _request(self, method, **kwargs): + resp = method.sync(client=self._client, **kwargs) + if isinstance(resp, Error): + raise RuntimeError(resp.errors) + + return resp diff --git a/jellyfish/_ws_notifier.py b/jellyfish/_ws_notifier.py index de46ee9..b06c4c3 100644 --- a/jellyfish/_ws_notifier.py +++ b/jellyfish/_ws_notifier.py @@ -3,21 +3,20 @@ """ import asyncio -from typing import Callable, Any +from typing import Any, Callable import betterproto - from websockets import client from websockets.exceptions import ConnectionClosed from jellyfish.events import ( ServerMessage, - ServerMessageAuthRequest, ServerMessageAuthenticated, - ServerMessageSubscribeRequest, + ServerMessageAuthRequest, ServerMessageEventType, - ServerMessageSubscribeResponse, ServerMessageMetricsReport, + ServerMessageSubscribeRequest, + ServerMessageSubscribeResponse, ) diff --git a/jellyfish/events/__init__.py b/jellyfish/events/__init__.py index 05e4b01..1190d0b 100644 --- a/jellyfish/events/__init__.py +++ b/jellyfish/events/__init__.py @@ -2,27 +2,24 @@ Server events being sent Jellyfish """ +# Exported messages # Private messages from jellyfish.events._protos.jellyfish import ( ServerMessage, ServerMessageAuthenticated, ServerMessageAuthRequest, - ServerMessageEventType, - ServerMessageSubscribeResponse, - ServerMessageSubscribeRequest, -) - -# Exported messages -from jellyfish.events._protos.jellyfish import ( ServerMessageComponentCrashed, + ServerMessageEventType, ServerMessageHlsPlayable, ServerMessageMetricsReport, - ServerMessagePeerCrashed, ServerMessagePeerConnected, + ServerMessagePeerCrashed, ServerMessagePeerDisconnected, ServerMessageRoomCrashed, - ServerMessageRoomDeleted, ServerMessageRoomCreated, + ServerMessageRoomDeleted, + ServerMessageSubscribeRequest, + ServerMessageSubscribeResponse, ) __all__ = [ diff --git a/openapi-python-client-config.yaml b/openapi-python-client-config.yaml new file mode 100644 index 0000000..b0cacfb --- /dev/null +++ b/openapi-python-client-config.yaml @@ -0,0 +1,2 @@ +project_name_override: jellyfish +package_name_override: _openapi_client \ No newline at end of file diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..4bd074c --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,977 @@ +# This file has been generated using OpenApiSpex. Do not edit manually! +# Run `mix api.spec` to regenerate + +--- +components: + responses: {} + schemas: + PeerStatus: + description: Informs about the peer status + enum: + - connected + - disconnected + example: disconnected + title: PeerStatus + type: string + x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Status + RoomDetailsResponse: + description: Response containing room details + properties: + data: + $ref: '#/components/schemas/Room' + required: + - data + title: RoomDetailsResponse + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.RoomDetailsResponse + ComponentOptionsRTSP: + description: Options specific to the RTSP component + properties: + keepAliveInterval: + default: 15000 + description: Interval (in ms) in which keep-alive RTSP messages will be sent to the remote stream source + minimum: 0 + type: integer + pierceNat: + default: true + description: Whether to attempt to create client-side NAT binding by sending an empty datagram from client to source, after the completion of RTSP setup + type: boolean + reconnectDelay: + default: 15000 + description: Delay (in ms) between successive reconnect attempts + minimum: 0 + type: integer + rtpPort: + default: 20000 + description: Local port RTP stream will be received at + maximum: 65535 + minimum: 1 + type: integer + sourceUri: + description: URI of RTSP source stream + example: rtsp://localhost:554/stream + type: string + required: + - sourceUri + title: ComponentOptionsRTSP + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.RTSP.Options + ComponentPropertiesHLS: + description: Properties specific to the HLS component + properties: + lowLatency: + description: Whether the component uses LL-HLS + type: boolean + persistent: + description: Whether the video is stored after end of stream + type: boolean + playable: + description: Whether the generated HLS playlist is playable + type: boolean + subscribeMode: + description: Whether the HLS component should subscribe to tracks automatically or manually + enum: + - auto + - manual + type: string + targetWindowDuration: + description: Duration of stream available for viewer + nullable: true + type: integer + required: + - playable + - lowLatency + - persistent + - targetWindowDuration + - subscribeMode + title: ComponentPropertiesHLS + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS.Properties + Room: + description: Description of the room state + properties: + components: + items: + $ref: '#/components/schemas/Component' + type: array + config: + $ref: '#/components/schemas/RoomConfig' + id: + description: Room ID + example: room-1 + type: string + peers: + items: + $ref: '#/components/schemas/Peer' + type: array + required: + - id + - config + - components + - peers + title: Room + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Room + Component: + description: Describes component + discriminator: + mapping: + file: '#/components/schemas/ComponentFile' + hls: '#/components/schemas/ComponentHLS' + rtsp: '#/components/schemas/ComponentRTSP' + propertyName: type + oneOf: + - $ref: '#/components/schemas/ComponentHLS' + - $ref: '#/components/schemas/ComponentRTSP' + - $ref: '#/components/schemas/ComponentFile' + title: Component + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component + PeerOptionsWebRTC: + description: Options specific to the WebRTC peer + properties: + enableSimulcast: + default: true + description: Enables the peer to use simulcast + type: boolean + title: PeerOptionsWebRTC + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.WebRTC + ComponentHLS: + description: Describes the HLS component + properties: + id: + description: Assigned component ID + example: component-1 + type: string + properties: + $ref: '#/components/schemas/ComponentPropertiesHLS' + type: + description: Component type + example: hls + type: string + required: + - id + - type + - properties + title: ComponentHLS + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS + HlsSkip: + description: Is delta manifest requested + enum: + - "YES" + example: "YES" + nullable: true + title: HlsSkip + type: string + x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Params.HlsSkip + ComponentFile: + description: Describes the File component + properties: + id: + description: Assigned component ID + example: component-1 + type: string + type: + description: Component type + example: file + type: string + required: + - id + - type + title: ComponentFile + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.File + SubscriptionConfig: + description: Subscription config + properties: + tracks: + description: List of tracks that hls endpoint will subscribe for + items: + $ref: '#/components/schemas/Track' + type: array + title: SubscriptionConfig + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Subscription.Tracks + HlsMsn: + description: Segment sequence number + example: 10 + minimum: 0 + nullable: true + title: HlsMsn + type: integer + x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Params.HlsMsn + ComponentRTSP: + description: Describes the RTSP component + properties: + id: + description: Assigned component ID + example: component-1 + type: string + properties: + $ref: '#/components/schemas/ComponentPropertiesRTSP' + type: + description: Component type + example: hls + type: string + required: + - id + - type + - properties + title: ComponentRTSP + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.RTSP + HlsPart: + description: Partial segment sequence number + example: 10 + minimum: 0 + nullable: true + title: HlsPart + type: integer + x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Params.HlsPart + ComponentDetailsResponse: + description: Response containing component details + properties: + data: + $ref: '#/components/schemas/Component' + required: + - data + title: ComponentDetailsResponse + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.ComponentDetailsResponse + ComponentOptionsHLS: + description: Options specific to the HLS component + properties: + lowLatency: + default: false + description: Whether the component should use LL-HLS + type: boolean + persistent: + default: false + description: Whether the video is stored after end of stream + type: boolean + s3: + description: Credentials to AWS S3 bucket. + nullable: true + oneOf: + - $ref: '#/components/schemas/S3Credentials' + type: object + subscribeMode: + default: auto + description: Whether the HLS component should subscribe to tracks automatically or manually. + enum: + - auto + - manual + type: string + targetWindowDuration: + description: Duration of stream available for viewer + nullable: true + type: integer + title: ComponentOptionsHLS + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS.Options + S3Credentials: + description: An AWS S3 credential that will be used to send HLS stream. The stream will only be uploaded if credentials are provided + properties: + accessKeyId: + description: An AWS access key identifier, linked to your AWS account. + type: string + bucket: + description: The name of the S3 bucket where your data will be stored. + type: string + region: + description: The AWS region where your bucket is located. + type: string + secretAccessKey: + description: The secret key that is linked to the Access Key ID. + type: string + required: + - accessKeyId + - secretAccessKey + - region + - bucket + title: S3Credentials + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS.S3 + RecordingListResponse: + description: Response containing list of all recording + properties: + data: + items: + type: string + type: array + required: + - data + title: RecordingListResponse + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.RecordingListResponse + ComponentOptions: + description: Component-specific options + oneOf: + - $ref: '#/components/schemas/ComponentOptionsHLS' + - $ref: '#/components/schemas/ComponentOptionsRTSP' + - $ref: '#/components/schemas/ComponentOptionsFile' + title: ComponentOptions + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.Options + Track: + description: Track id + example: track-1 + title: Track + type: string + x-struct: Elixir.JellyfishWeb.ApiSpec.Subscription.Track + ComponentPropertiesRTSP: + description: Properties specific to the RTSP component + properties: {} + title: ComponentPropertiesRTSP + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.RTSP.Properties + PeerOptions: + description: Peer-specific options + oneOf: + - $ref: '#/components/schemas/PeerOptionsWebRTC' + title: PeerOptions + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Options + Peer: + description: Describes peer status + properties: + id: + description: Assigned peer id + example: peer-1 + type: string + status: + $ref: '#/components/schemas/PeerStatus' + type: + $ref: '#/components/schemas/PeerType' + required: + - id + - type + - status + title: Peer + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Peer + ComponentType: + description: Component type + example: hls + title: ComponentType + type: string + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.Type + AuthToken: + description: Token for authorizing websocket connection + example: 5cdac726-57a3-4ecb-b1d5-72a3d62ec242 + title: AuthToken + type: string + x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Token + RoomsListingResponse: + description: Response containing list of all rooms + properties: + data: + items: + $ref: '#/components/schemas/Room' + type: array + required: + - data + title: RoomsListingResponse + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.RoomsListingResponse + PeerDetailsResponse: + description: Response containing peer details and their token + properties: + data: + properties: + peer: + $ref: '#/components/schemas/Peer' + token: + $ref: '#/components/schemas/AuthToken' + required: + - peer + - token + type: object + required: + - data + title: PeerDetailsResponse + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.PeerDetailsResponse + HlsResponse: + description: Requested file + title: HlsResponse + type: string + x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Response + PeerType: + description: Peer type + example: webrtc + title: PeerType + type: string + x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Type + RoomCreateDetailsResponse: + description: Response containing room details + properties: + data: + properties: + jellyfish_address: + description: Jellyfish instance address where the room was created. This might be different than the address of Jellyfish where the request was sent only when running a cluster of Jellyfishes. + example: jellyfish1:5003 + type: string + room: + $ref: '#/components/schemas/Room' + required: + - room + - jellyfish_address + type: object + required: + - data + title: RoomCreateDetailsResponse + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.RoomCreateDetailsResponse + ComponentOptionsFile: + description: Options specific to the File component + properties: + filePath: + description: Path to track file. Must be either OPUS encapsulated in Ogg or raw h264 + example: /root/video.h264 + type: string + required: + - filePath + title: ComponentOptionsFile + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Component.File.Options + Error: + description: Error message + properties: + errors: + description: Error details + example: Token has expired + type: string + required: + - errors + title: Error + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Error + RoomConfig: + description: Room configuration + properties: + maxPeers: + description: Maximum amount of peers allowed into the room + example: 10 + minimum: 1 + nullable: true + type: integer + videoCodec: + description: Enforces video codec for each peer in the room + enum: + - h264 + - vp8 + nullable: true + type: string + webhookUrl: + description: URL where Jellyfish notifications will be sent + example: https://backend.address.com/jellyfish-notifications-endpoint + nullable: true + type: string + title: RoomConfig + type: object + x-struct: Elixir.JellyfishWeb.ApiSpec.Room.Config + securitySchemes: + authorization: + scheme: bearer + type: http +info: + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + title: Jellyfish Media Server + version: 0.2.0 +openapi: 3.0.0 +paths: + /hls/{room_id}/subscribe: + post: + callbacks: {} + operationId: subscribe_tracks + parameters: + - description: Room ID + in: path + name: room_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SubscriptionConfig' + description: Subscribe configuration + required: false + responses: + '201': + description: Tracks succesfully added. + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid request structure + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Room doesn't exist + summary: Subscribe hls component for tracks + tags: + - hls + /hls/{room_id}/{filename}: + get: + callbacks: {} + operationId: getHlsContent + parameters: + - description: Room id + in: path + name: room_id + required: true + schema: + type: string + - description: Name of the file + in: path + name: filename + required: true + schema: + type: string + - description: Byte range of partial segment + in: header + name: range + required: false + schema: + type: string + - description: Segment sequence number + in: query + name: _HLS_msn + required: false + schema: + $ref: '#/components/schemas/HlsMsn' + - description: Partial segment sequence number + in: query + name: _HLS_part + required: false + schema: + $ref: '#/components/schemas/HlsPart' + - description: Is delta manifest requested + in: query + name: _HLS_skip + required: false + schema: + $ref: '#/components/schemas/HlsSkip' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/HlsResponse' + description: File was found + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid filename + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: File not found + summary: Retrieve HLS Content + tags: + - hls + /recording: + get: + callbacks: {} + operationId: get_recordings + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RecordingListResponse' + description: Success + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unable to obtain recordings + summary: Lists all available recordings + tags: + - recording + /recording/{recording_id}: + delete: + callbacks: {} + operationId: delete_recording + parameters: + - description: Recording id + in: path + name: recording_id + required: true + schema: + type: string + responses: + '204': + description: Successfully deleted recording + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid recording + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Recording doesn't exist + summary: Deletes the recording + tags: + - recording + /recording/{recording_id}/{filename}: + get: + callbacks: {} + operationId: getRecordingContent + parameters: + - description: Recording id + in: path + name: recording_id + required: true + schema: + type: string + - description: Name of the file + in: path + name: filename + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/HlsResponse' + description: File was found + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid request + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: File not found + summary: Retrieve Recording (HLS) Content + tags: + - recording + /room: + get: + callbacks: {} + operationId: get_all_rooms + parameters: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RoomsListingResponse' + description: Success + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + summary: Show information about all rooms + tags: + - room + post: + callbacks: {} + operationId: create_room + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RoomConfig' + description: Room configuration + required: false + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/RoomCreateDetailsResponse' + description: Room successfully created + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid request structure + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + summary: Creates a room + tags: + - room + /room/{room_id}: + delete: + callbacks: {} + operationId: delete_room + parameters: + - description: Room id + in: path + name: room_id + required: true + schema: + type: string + responses: + '204': + description: Successfully deleted room + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Room doesn't exist + summary: Delete the room + tags: + - room + get: + callbacks: {} + operationId: get_room + parameters: + - description: Room ID + in: path + name: room_id + required: true + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RoomDetailsResponse' + description: Success + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Room doesn't exist + summary: Shows information about the room + tags: + - room + /room/{room_id}/component: + post: + callbacks: {} + operationId: add_component + parameters: + - description: Room ID + in: path + name: room_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + options: + $ref: '#/components/schemas/ComponentOptions' + type: + $ref: '#/components/schemas/ComponentType' + required: + - type + type: object + description: Component config + required: false + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/ComponentDetailsResponse' + description: Successfully added component + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid request + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Room doesn't exist + summary: Creates the component and adds it to the room + tags: + - room + /room/{room_id}/component/{id}: + delete: + callbacks: {} + operationId: delete_component + parameters: + - description: Room ID + in: path + name: room_id + required: true + schema: + type: string + - description: Component ID + in: path + name: id + required: true + schema: + type: string + responses: + '204': + description: Successfully deleted + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Either component or the room doesn't exist + summary: Delete the component from the room + tags: + - room + /room/{room_id}/peer: + post: + callbacks: {} + operationId: add_peer + parameters: + - description: Room id + in: path + name: room_id + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + properties: + options: + $ref: '#/components/schemas/PeerOptions' + type: + $ref: '#/components/schemas/PeerType' + required: + - type + - options + type: object + description: Peer specification + required: false + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/PeerDetailsResponse' + description: Peer successfully created + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Invalid request body structure + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Room doesn't exist + '503': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Peer limit has been reached + summary: Create peer + tags: + - room + /room/{room_id}/peer/{id}: + delete: + callbacks: {} + operationId: delete_peer + parameters: + - description: Room ID + in: path + name: room_id + required: true + schema: + type: string + - description: Peer id + in: path + name: id + required: true + schema: + type: string + responses: + '204': + description: Peer successfully deleted + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Room ID or Peer ID references a resource that doesn't exist + summary: Delete peer + tags: + - room +security: + - authorization: [] +servers: [] +tags: [] \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index d8f8dd6..9ba6dc6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -12,6 +12,41 @@ files = [ {file = "aenum-3.1.15.tar.gz", hash = "sha256:8cbd76cd18c4f870ff39b24284d3ea028fbe8731a58df3aa581e434c575b9559"}, ] +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + +[[package]] +name = "anyio" +version = "4.1.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.1.0-py3-none-any.whl", hash = "sha256:56a415fbc462291813a94528a779597226619c8e78af7de0507333f700011e5f"}, + {file = "anyio-4.1.0.tar.gz", hash = "sha256:5a0bec7085176715be77df87fc66d6c9d70626bd752fcc85f57cdbee5b3760da"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + [[package]] name = "astroid" version = "2.15.8" @@ -46,6 +81,39 @@ files = [ six = ">=1.6.1,<2.0" wheel = ">=0.23.0,<1.0" +[[package]] +name = "attrs" +version = "23.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] + +[[package]] +name = "autoflake" +version = "2.2.1" +description = "Removes unused imports and unused variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "autoflake-2.2.1-py3-none-any.whl", hash = "sha256:265cde0a43c1f44ecfb4f30d95b0437796759d07be7706a2f70e4719234c0f79"}, + {file = "autoflake-2.2.1.tar.gz", hash = "sha256:62b7b6449a692c3c9b0c916919bbc21648da7281e8506bcf8d3f8280e431ebc1"}, +] + +[package.dependencies] +pyflakes = ">=3.0.0" +tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} + [[package]] name = "betterproto" version = "2.0.0b6" @@ -69,29 +137,33 @@ compiler = ["black (>=19.3b0)", "isort (>=5.11.5,<6.0.0)", "jinja2 (>=3.0.3)"] [[package]] name = "black" -version = "23.11.0" +version = "23.12.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, - {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, - {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, - {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, - {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, - {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, - {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, - {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, - {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, - {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, - {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, - {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, - {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, - {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, - {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, - {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, - {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, - {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, + {file = "black-23.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67f19562d367468ab59bd6c36a72b2c84bc2f16b59788690e02bbcb140a77175"}, + {file = "black-23.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbd75d9f28a7283b7426160ca21c5bd640ca7cd8ef6630b4754b6df9e2da8462"}, + {file = "black-23.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593596f699ca2dcbbbdfa59fcda7d8ad6604370c10228223cd6cf6ce1ce7ed7e"}, + {file = "black-23.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:12d5f10cce8dc27202e9a252acd1c9a426c83f95496c959406c96b785a92bb7d"}, + {file = "black-23.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e73c5e3d37e5a3513d16b33305713237a234396ae56769b839d7c40759b8a41c"}, + {file = "black-23.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba09cae1657c4f8a8c9ff6cfd4a6baaf915bb4ef7d03acffe6a2f6585fa1bd01"}, + {file = "black-23.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace64c1a349c162d6da3cef91e3b0e78c4fc596ffde9413efa0525456148873d"}, + {file = "black-23.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:72db37a2266b16d256b3ea88b9affcdd5c41a74db551ec3dd4609a59c17d25bf"}, + {file = "black-23.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fdf6f23c83078a6c8da2442f4d4eeb19c28ac2a6416da7671b72f0295c4a697b"}, + {file = "black-23.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39dda060b9b395a6b7bf9c5db28ac87b3c3f48d4fdff470fa8a94ab8271da47e"}, + {file = "black-23.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7231670266ca5191a76cb838185d9be59cfa4f5dd401b7c1c70b993c58f6b1b5"}, + {file = "black-23.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:193946e634e80bfb3aec41830f5d7431f8dd5b20d11d89be14b84a97c6b8bc75"}, + {file = "black-23.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcf91b01ddd91a2fed9a8006d7baa94ccefe7e518556470cf40213bd3d44bbbc"}, + {file = "black-23.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:996650a89fe5892714ea4ea87bc45e41a59a1e01675c42c433a35b490e5aa3f0"}, + {file = "black-23.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdbff34c487239a63d86db0c9385b27cdd68b1bfa4e706aa74bb94a435403672"}, + {file = "black-23.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:97af22278043a6a1272daca10a6f4d36c04dfa77e61cbaaf4482e08f3640e9f0"}, + {file = "black-23.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ead25c273adfad1095a8ad32afdb8304933efba56e3c1d31b0fee4143a1e424a"}, + {file = "black-23.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c71048345bdbced456cddf1622832276d98a710196b842407840ae8055ade6ee"}, + {file = "black-23.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a832b6e00eef2c13b3239d514ea3b7d5cc3eaa03d0474eedcbbda59441ba5d"}, + {file = "black-23.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:6a82a711d13e61840fb11a6dfecc7287f2424f1ca34765e70c909a35ffa7fb95"}, + {file = "black-23.12.0-py3-none-any.whl", hash = "sha256:a7c07db8200b5315dc07e331dda4d889a56f6bf4db6a9c2a526fa3166a81614f"}, + {file = "black-23.12.0.tar.gz", hash = "sha256:330a327b422aca0634ecd115985c1c7fd7bdb5b5a2ef8aa9888a82e2ebe9437a"}, ] [package.dependencies] @@ -105,7 +177,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -122,13 +194,13 @@ files = [ [[package]] name = "certifi" -version = "2023.7.22" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] @@ -271,13 +343,13 @@ graph = ["objgraph (>=1.7.2)"] [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -340,6 +412,17 @@ multidict = "*" [package.extras] protobuf = ["protobuf (>=3.20.0)"] +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + [[package]] name = "h2" version = "4.1.0" @@ -366,6 +449,51 @@ files = [ {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, ] +[[package]] +name = "httpcore" +version = "1.0.2" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, + {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.23.0)"] + +[[package]] +name = "httpx" +version = "0.25.2" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.25.2-py3-none-any.whl", hash = "sha256:a05d3d052d9b2dfce0e3896636467f8a5342fb2b902c819428e1ac65413ca118"}, + {file = "httpx-0.25.2.tar.gz", hash = "sha256:8b8fcaa0c8ea7b05edd69a094e63a2094c4efcb48129fb757361bc423c0ad9e8"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + [[package]] name = "hyperframe" version = "6.0.1" @@ -379,31 +507,31 @@ files = [ [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "7.0.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, + {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] @@ -438,21 +566,15 @@ files = [ [[package]] name = "isort" -version = "5.12.0" +version = "5.13.1" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, + {file = "isort-5.13.1-py3-none-any.whl", hash = "sha256:56a51732c25f94ca96f6721be206dd96a95f42950502eb26c1015d333bc6edb7"}, + {file = "isort-5.13.1.tar.gz", hash = "sha256:aaed790b463e8703fb1eddb831dfa8e8616bacde2c083bd557ef73c8189b7263"}, ] -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [[package]] name = "itsdangerous" version = "2.1.2" @@ -784,6 +906,31 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "openapi-python-client" +version = "0.15.2" +description = "Generate modern Python clients from OpenAPI" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "openapi_python_client-0.15.2-py3-none-any.whl", hash = "sha256:240ff6e571eecd81758410cb743c24b6cabc4d30a3fd79cd886feeb8960610c5"}, + {file = "openapi_python_client-0.15.2.tar.gz", hash = "sha256:a0ff88cd142f907277c333fa4e3bb9461ebfd8e58bad1bbccdd8f14dc3c311e7"}, +] + +[package.dependencies] +attrs = ">=21.3.0" +autoflake = ">=1.4,<3.0.0" +black = ">=23" +colorama = {version = ">=0.4.3,<0.5.0", markers = "sys_platform == \"win32\""} +httpx = ">=0.20.0,<0.26.0" +isort = ">=5.0.5,<6.0.0" +jinja2 = ">=3.0.0,<4.0.0" +pydantic = ">=2.1.1,<3.0.0" +python-dateutil = ">=2.8.1,<3.0.0" +PyYAML = ">=6.0,<7.0" +shellingham = ">=1.3.2,<2.0.0" +typer = ">0.6,<0.10" + [[package]] name = "packaging" version = "23.2" @@ -797,13 +944,13 @@ files = [ [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] @@ -828,13 +975,13 @@ dev = ["black", "hypothesis", "mypy", "pygments (>=2.14.0)", "pytest", "pytest-c [[package]] name = "platformdirs" -version = "4.0.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, - {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] [package.extras] @@ -858,69 +1005,165 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "1.10.13" -description = "Data validation and settings management using python type hints" +version = "2.5.2" +description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:efff03cc7a4f29d9009d1c96ceb1e7a70a65cfe86e89d34e4a5f2ab1e5693737"}, - {file = "pydantic-1.10.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ecea2b9d80e5333303eeb77e180b90e95eea8f765d08c3d278cd56b00345d01"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1740068fd8e2ef6eb27a20e5651df000978edce6da6803c2bef0bc74540f9548"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84bafe2e60b5e78bc64a2941b4c071a4b7404c5c907f5f5a99b0139781e69ed8"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc0898c12f8e9c97f6cd44c0ed70d55749eaf783716896960b4ecce2edfd2d69"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:654db58ae399fe6434e55325a2c3e959836bd17a6f6a0b6ca8107ea0571d2e17"}, - {file = "pydantic-1.10.13-cp310-cp310-win_amd64.whl", hash = "sha256:75ac15385a3534d887a99c713aa3da88a30fbd6204a5cd0dc4dab3d770b9bd2f"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c553f6a156deb868ba38a23cf0df886c63492e9257f60a79c0fd8e7173537653"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e08865bc6464df8c7d61439ef4439829e3ab62ab1669cddea8dd00cd74b9ffe"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31647d85a2013d926ce60b84f9dd5300d44535a9941fe825dc349ae1f760df9"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:210ce042e8f6f7c01168b2d84d4c9eb2b009fe7bf572c2266e235edf14bacd80"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8ae5dd6b721459bfa30805f4c25880e0dd78fc5b5879f9f7a692196ddcb5a580"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f8e81fc5fb17dae698f52bdd1c4f18b6ca674d7068242b2aff075f588301bbb0"}, - {file = "pydantic-1.10.13-cp311-cp311-win_amd64.whl", hash = "sha256:61d9dce220447fb74f45e73d7ff3b530e25db30192ad8d425166d43c5deb6df0"}, - {file = "pydantic-1.10.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4b03e42ec20286f052490423682016fd80fda830d8e4119f8ab13ec7464c0132"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59ef915cac80275245824e9d771ee939133be38215555e9dc90c6cb148aaeb5"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a1f9f747851338933942db7af7b6ee8268568ef2ed86c4185c6ef4402e80ba8"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:97cce3ae7341f7620a0ba5ef6cf043975cd9d2b81f3aa5f4ea37928269bc1b87"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854223752ba81e3abf663d685f105c64150873cc6f5d0c01d3e3220bcff7d36f"}, - {file = "pydantic-1.10.13-cp37-cp37m-win_amd64.whl", hash = "sha256:b97c1fac8c49be29486df85968682b0afa77e1b809aff74b83081cc115e52f33"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c958d053453a1c4b1c2062b05cd42d9d5c8eb67537b8d5a7e3c3032943ecd261"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c5370a7edaac06daee3af1c8b1192e305bc102abcbf2a92374b5bc793818599"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6f6e7305244bddb4414ba7094ce910560c907bdfa3501e9db1a7fd7eaea127"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3a3c792a58e1622667a2837512099eac62490cdfd63bd407993aaf200a4cf1f"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c636925f38b8db208e09d344c7aa4f29a86bb9947495dd6b6d376ad10334fb78"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:678bcf5591b63cc917100dc50ab6caebe597ac67e8c9ccb75e698f66038ea953"}, - {file = "pydantic-1.10.13-cp38-cp38-win_amd64.whl", hash = "sha256:6cf25c1a65c27923a17b3da28a0bdb99f62ee04230c931d83e888012851f4e7f"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ef467901d7a41fa0ca6db9ae3ec0021e3f657ce2c208e98cd511f3161c762c6"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968ac42970f57b8344ee08837b62f6ee6f53c33f603547a55571c954a4225691"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9849f031cf8a2f0a928fe885e5a04b08006d6d41876b8bbd2fc68a18f9f2e3fd"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56e3ff861c3b9c6857579de282ce8baabf443f42ffba355bf070770ed63e11e1"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f00790179497767aae6bcdc36355792c79e7bbb20b145ff449700eb076c5f96"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:75b297827b59bc229cac1a23a2f7a4ac0031068e5be0ce385be1462e7e17a35d"}, - {file = "pydantic-1.10.13-cp39-cp39-win_amd64.whl", hash = "sha256:e70ca129d2053fb8b728ee7d1af8e553a928d7e301a311094b8a0501adc8763d"}, - {file = "pydantic-1.10.13-py3-none-any.whl", hash = "sha256:b87326822e71bd5f313e7d3bfdc77ac3247035ac10b0c0618bd99dcf95b1e687"}, - {file = "pydantic-1.10.13.tar.gz", hash = "sha256:32c8b48dcd3b2ac4e78b0ba4af3a2c2eb6048cb75202f0ea7b34feb740efc340"}, + {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, + {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, ] [package.dependencies] -typing-extensions = ">=4.2.0" +annotated-types = ">=0.4.0" +pydantic-core = "2.14.5" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.14.5" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, + {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, + {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, + {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, + {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, + {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, + {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, + {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, + {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, + {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, + {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, + {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, + {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, + {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, + {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, + {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pyflakes" +version = "3.1.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, + {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, +] [[package]] name = "pygments" -version = "2.16.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pylint" @@ -1113,6 +1356,43 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "ruff" +version = "0.1.7" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"}, + {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"}, + {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"}, + {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"}, + {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"}, + {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"}, + {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"}, + {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"}, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + [[package]] name = "six" version = "1.16.0" @@ -1124,6 +1404,17 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + [[package]] name = "tomli" version = "2.0.1" @@ -1137,24 +1428,45 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.2" +version = "0.12.3" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.2-py3-none-any.whl", hash = "sha256:eeea7ac7563faeab0a1ed8fe12c2e5a51c61f933f2502f7e9db0241a65163ad0"}, - {file = "tomlkit-0.12.2.tar.gz", hash = "sha256:df32fab589a81f0d7dc525a4267b6d7a64ee99619cbd1eeb0fae32c1dd426977"}, + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, ] +[[package]] +name = "typer" +version = "0.9.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.6" +files = [ + {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, + {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.9.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] @@ -1324,13 +1636,13 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "wheel" -version = "0.41.3" +version = "0.42.0" description = "A built-package format for Python" optional = false python-versions = ">=3.7" files = [ - {file = "wheel-0.41.3-py3-none-any.whl", hash = "sha256:488609bc63a29322326e05560731bf7bfea8e48ad646e1f5e40d366607de0942"}, - {file = "wheel-0.41.3.tar.gz", hash = "sha256:4d4987ce51a49370ea65c0bfd2234e8ce80a12780820d9dc462597a6e60d0841"}, + {file = "wheel-0.42.0-py3-none-any.whl", hash = "sha256:177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d"}, + {file = "wheel-0.42.0.tar.gz", hash = "sha256:c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8"}, ] [package.extras] @@ -1433,4 +1745,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "19e4eba5fe6c55f6175f688fbe084c73ad023d646b1a701c5e7f85c7fbd8ec11" +content-hash = "ba451508068251b74f4d0db73ad670e8fd050507b300a3b4605fde3923086696" diff --git a/pyproject.toml b/pyproject.toml index 3267f55..e66854f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ packages = [{ include = "jellyfish" }] python = "^3.8" websockets = "^11.0.3" urllib3 = ">=1.25.3,<2" -pydantic = "<2" aenum = "^3.1.15" python-dateutil = "^2.8.2" betterproto = "2.0.0b6" @@ -25,6 +24,8 @@ black = "^23.10.0" pdoc = "^14.1.0" mkdocs = "^1.5.3" mike = "^2.0.0" +openapi-python-client = "^0.15.2" +ruff = "^0.1.6" [tool.poetry.group.test.dependencies] pytest = "^7.4.2" diff --git a/tests/test_notifier.py b/tests/test_notifier.py index 519a207..b04c881 100644 --- a/tests/test_notifier.py +++ b/tests/test_notifier.py @@ -86,7 +86,19 @@ def room_api(): @pytest.fixture def notifier(): - return Notifier(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) + notifier = Notifier( + server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN + ) + + @notifier.on_server_notification + def handle_notification(_server_notification): + pass + + @notifier.on_metrics + def handle_metrics(_metrics_report): + pass + + return notifier class TestReceivingNotifications: diff --git a/tests/test_recording_api.py b/tests/test_recording_api.py index 30b1fe4..8d03f8d 100644 --- a/tests/test_recording_api.py +++ b/tests/test_recording_api.py @@ -5,7 +5,8 @@ import pytest from jellyfish import RecordingApi -from jellyfish import NotFoundException + +# from jellyfish import NotFoundException HOST = "jellyfish" if os.getenv("DOCKER_TEST") == "TRUE" else "localhost" @@ -28,5 +29,5 @@ def test_valid(self, recording_api: RecordingApi): class TestDelete: def test_invalid_recording(self, recording_api: RecordingApi): - with pytest.raises(NotFoundException): + with pytest.raises(Exception): recording_api.delete("invalid-id") diff --git a/tests/test_room_api.py b/tests/test_room_api.py index 14142d0..cfc5140 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -6,12 +6,16 @@ import pytest from jellyfish import RoomApi, RoomConfig -from jellyfish import Room -from jellyfish import ComponentOptionsRTSP, ComponentOptionsHLS, PeerOptionsWebRTC +from jellyfish import Room, ComponentHLS, ComponentRTSP +from jellyfish import ( + ComponentOptionsRTSP, + ComponentOptionsHLS, + ComponentOptionsHLSSubscribeMode, + PeerOptionsWebRTC, +) -from jellyfish import ValidationError -from jellyfish import UnauthorizedException, NotFoundException, BadRequestException +# from jellyfish import UnauthorizedException, NotFoundException, BadRequestException HOST = "jellyfish" if os.getenv("DOCKER_TEST") == "TRUE" else "localhost" @@ -27,7 +31,7 @@ HLS_OPTIONS = ComponentOptionsHLS() RTSP_OPTIONS = ComponentOptionsRTSP( - sourceUri="rtsp://ef36c6dff23ecc5bbe311cc880d95dc8.se:2137/does/not/matter" + source_uri="rtsp://ef36c6dff23ecc5bbe311cc880d95dc8.se:2137/does/not/matter" ) @@ -35,7 +39,7 @@ class TestAuthentication: def test_invalid_token(self): room_api = RoomApi(server_address=SERVER_ADDRESS, server_api_token="invalid") - with pytest.raises(UnauthorizedException): + with pytest.raises(RuntimeError): room_api.create_room() def test_valid_token(self): @@ -89,11 +93,11 @@ def test_valid_params(self, room_api): assert room in room_api.get_all_rooms() def test_invalid_max_peers(self, room_api): - with pytest.raises(ValidationError): + with pytest.raises(RuntimeError): room_api.create_room(max_peers="10", video_codec=CODEC_H264) def test_invalid_video_codec(self, room_api): - with pytest.raises(ValidationError): + with pytest.raises(ValueError): room_api.create_room(max_peers=MAX_PEERS, video_codec="h420") @@ -105,7 +109,7 @@ def test_valid(self, room_api): assert room not in room_api.get_all_rooms() def test_invalid(self, room_api): - with pytest.raises(NotFoundException): + with pytest.raises(RuntimeError): room_api.delete_room("invalid_id") @@ -126,11 +130,11 @@ def test_valid(self, room_api: RoomApi): components=[], peers=[], id=room.id, - config=RoomConfig(maxPeers=None, videoCodec=None), + config=RoomConfig(max_peers=None, video_codec=None), ) == room_api.get_room(room.id) def test_invalid(self, room_api: RoomApi): - with pytest.raises(NotFoundException): + with pytest.raises(RuntimeError): room_api.get_room("invalid_id") @@ -140,16 +144,16 @@ def test_with_options_hls(self, room_api: RoomApi): room_api.add_component(room.id, options=HLS_OPTIONS) - component = room_api.get_room(room.id).components[0].actual_instance + component = room_api.get_room(room.id).components[0] - assert component.type == COMPONENT_HLS + assert isinstance(component, ComponentHLS) def test_with_options_rtsp(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) room_api.add_component(room.id, options=RTSP_OPTIONS) - component = room_api.get_room(room.id).components[0].actual_instance - assert component.type == COMPONENT_RTSP + component = room_api.get_room(room.id).components[0] + assert isinstance(component, ComponentRTSP) def test_invalid_type(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) @@ -161,7 +165,7 @@ def test_invalid_type(self, room_api: RoomApi): class TestDeleteComponent: def test_valid_component(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) - component = room_api.add_component(room.id, options=HLS_OPTIONS).actual_instance + component = room_api.add_component(room.id, options=HLS_OPTIONS) room_api.delete_component(room.id, component.id) assert [] == room_api.get_room(room.id).components @@ -169,7 +173,7 @@ def test_valid_component(self, room_api: RoomApi): def test_invalid_component(self, room_api: RoomApi): _, room = room_api.create_room() - with pytest.raises(NotFoundException): + with pytest.raises(RuntimeError): room_api.delete_component(room.id, "invalid_id") @@ -177,14 +181,17 @@ class TestHLSSubscribe: def test_valid_subscription(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) _ = room_api.add_component( - room.id, options=ComponentOptionsHLS(subscribe_mode="manual") + room.id, + options=ComponentOptionsHLS( + subscribe_mode=ComponentOptionsHLSSubscribeMode("manual") + ), ) assert room_api.hls_subscribe(room.id, ["track-id"]) is None def test_invalid_subscription(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) _ = room_api.add_component(room.id, options=HLS_OPTIONS) - with pytest.raises(BadRequestException): + with pytest.raises(RuntimeError): room_api.hls_subscribe(room.id, ["track-id"]) @@ -200,7 +207,7 @@ def test_with_specified_options(self, room_api: RoomApi): _, room = room_api.create_room() _token, peer = room_api.add_peer( - room.id, options=PeerOptionsWebRTC(enableSimulcast=True) + room.id, options=PeerOptionsWebRTC(enable_simulcast=True) ) self._assert_peer_created(room_api, peer, room.id) @@ -217,7 +224,7 @@ class TestDeletePeer: def test_valid(self, room_api: RoomApi): _, room = room_api.create_room() _, peer = room_api.add_peer( - room.id, options=PeerOptionsWebRTC(enableSimulcast=True) + room.id, options=PeerOptionsWebRTC(enable_simulcast=True) ) room_api.delete_peer(room.id, peer.id) @@ -227,5 +234,5 @@ def test_valid(self, room_api: RoomApi): def test_invalid(self, room_api: RoomApi): _, room = room_api.create_room() - with pytest.raises(NotFoundException): + with pytest.raises(RuntimeError): room_api.delete_peer(room.id, peer_id="invalid_peer_id") From e7e17277c664fc2c6d46039b7b2f6eb300b72e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Wed, 13 Dec 2023 12:17:47 +0100 Subject: [PATCH 2/9] Fix ruff --- jellyfish/__init__.py | 6 +-- .../api/hls/get_hls_content.py | 25 +++++------- .../api/hls/subscribe_tracks.py | 2 - .../api/recording/delete_recording.py | 2 - .../api/recording/get_recording_content.py | 2 - .../api/recording/get_recordings.py | 2 - .../_openapi_client/api/room/add_component.py | 2 - .../_openapi_client/api/room/add_peer.py | 2 - .../_openapi_client/api/room/create_room.py | 2 - .../api/room/delete_component.py | 2 - .../_openapi_client/api/room/delete_peer.py | 2 - .../_openapi_client/api/room/delete_room.py | 2 - .../_openapi_client/api/room/get_all_rooms.py | 2 - .../_openapi_client/api/room/get_room.py | 2 - jellyfish/_openapi_client/models/__init__.py | 2 - jellyfish/_openapi_client/models/hls_skip.py | 8 ---- poetry.lock | 39 +++---------------- test_commands.py => poetry_scripts.py | 12 ++++-- pyproject.toml | 20 ++++++---- 19 files changed, 40 insertions(+), 96 deletions(-) delete mode 100644 jellyfish/_openapi_client/models/hls_skip.py rename test_commands.py => poetry_scripts.py (84%) diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index b5ef76b..6029d26 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -19,15 +19,13 @@ Room, RoomConfig, RoomConfigVideoCodec, - Error, ) +from jellyfish._recording_api import RecordingApi +from jellyfish._room_api import RoomApi # API from jellyfish._webhook_notifier import receive_json from jellyfish._ws_notifier import Notifier -from jellyfish._recording_api import RecordingApi -from jellyfish._room_api import RoomApi - __all__ = [ "RoomApi", diff --git a/jellyfish/_openapi_client/api/hls/get_hls_content.py b/jellyfish/_openapi_client/api/hls/get_hls_content.py index 8887a32..fd4d641 100644 --- a/jellyfish/_openapi_client/api/hls/get_hls_content.py +++ b/jellyfish/_openapi_client/api/hls/get_hls_content.py @@ -6,7 +6,6 @@ from ... import errors from ...client import AuthenticatedClient, Client from ...models.error import Error -from ...models.hls_skip import HlsSkip from ...types import UNSET, Response, Unset @@ -16,7 +15,7 @@ def _get_kwargs( *, field_hls_msn: Union[Unset, None, int] = UNSET, field_hls_part: Union[Unset, None, int] = UNSET, - field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + field_hls_skip: Union[Unset, None, str] = UNSET, range_: Union[Unset, str] = UNSET, ) -> Dict[str, Any]: headers = {} @@ -28,11 +27,7 @@ def _get_kwargs( params["_HLS_part"] = field_hls_part - json_field_hls_skip: Union[Unset, None, str] = UNSET - if not isinstance(field_hls_skip, Unset): - json_field_hls_skip = field_hls_skip.value if field_hls_skip else None - - params["_HLS_skip"] = json_field_hls_skip + params["_HLS_skip"] = field_hls_skip params = {k: v for k, v in params.items() if v is not UNSET and v is not None} @@ -85,7 +80,7 @@ def sync_detailed( client: Union[AuthenticatedClient, Client], field_hls_msn: Union[Unset, None, int] = UNSET, field_hls_part: Union[Unset, None, int] = UNSET, - field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + field_hls_skip: Union[Unset, None, str] = UNSET, range_: Union[Unset, str] = UNSET, ) -> Response[Union[Error, str]]: """Retrieve HLS Content @@ -95,7 +90,7 @@ def sync_detailed( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. range_ (Union[Unset, str]): Raises: @@ -129,7 +124,7 @@ def sync( client: Union[AuthenticatedClient, Client], field_hls_msn: Union[Unset, None, int] = UNSET, field_hls_part: Union[Unset, None, int] = UNSET, - field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + field_hls_skip: Union[Unset, None, str] = UNSET, range_: Union[Unset, str] = UNSET, ) -> Optional[Union[Error, str]]: """Retrieve HLS Content @@ -139,7 +134,7 @@ def sync( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. range_ (Union[Unset, str]): Raises: @@ -168,7 +163,7 @@ async def asyncio_detailed( client: Union[AuthenticatedClient, Client], field_hls_msn: Union[Unset, None, int] = UNSET, field_hls_part: Union[Unset, None, int] = UNSET, - field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + field_hls_skip: Union[Unset, None, str] = UNSET, range_: Union[Unset, str] = UNSET, ) -> Response[Union[Error, str]]: """Retrieve HLS Content @@ -178,7 +173,7 @@ async def asyncio_detailed( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. range_ (Union[Unset, str]): Raises: @@ -210,7 +205,7 @@ async def asyncio( client: Union[AuthenticatedClient, Client], field_hls_msn: Union[Unset, None, int] = UNSET, field_hls_part: Union[Unset, None, int] = UNSET, - field_hls_skip: Union[Unset, None, HlsSkip] = UNSET, + field_hls_skip: Union[Unset, None, str] = UNSET, range_: Union[Unset, str] = UNSET, ) -> Optional[Union[Error, str]]: """Retrieve HLS Content @@ -220,7 +215,7 @@ async def asyncio( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, HlsSkip]): Is delta manifest requested Example: YES. + field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. range_ (Union[Unset, str]): Raises: diff --git a/jellyfish/_openapi_client/api/hls/subscribe_tracks.py b/jellyfish/_openapi_client/api/hls/subscribe_tracks.py index c963f34..2038556 100644 --- a/jellyfish/_openapi_client/api/hls/subscribe_tracks.py +++ b/jellyfish/_openapi_client/api/hls/subscribe_tracks.py @@ -15,8 +15,6 @@ def _get_kwargs( *, json_body: SubscriptionConfig, ) -> Dict[str, Any]: - pass - json_json_body = json_body.to_dict() return { diff --git a/jellyfish/_openapi_client/api/recording/delete_recording.py b/jellyfish/_openapi_client/api/recording/delete_recording.py index 51bc34a..ae6ba21 100644 --- a/jellyfish/_openapi_client/api/recording/delete_recording.py +++ b/jellyfish/_openapi_client/api/recording/delete_recording.py @@ -12,8 +12,6 @@ def _get_kwargs( recording_id: str, ) -> Dict[str, Any]: - pass - return { "method": "delete", "url": "/recording/{recording_id}".format( diff --git a/jellyfish/_openapi_client/api/recording/get_recording_content.py b/jellyfish/_openapi_client/api/recording/get_recording_content.py index 56ced1b..436b522 100644 --- a/jellyfish/_openapi_client/api/recording/get_recording_content.py +++ b/jellyfish/_openapi_client/api/recording/get_recording_content.py @@ -13,8 +13,6 @@ def _get_kwargs( recording_id: str, filename: str, ) -> Dict[str, Any]: - pass - return { "method": "get", "url": "/recording/{recording_id}/{filename}".format( diff --git a/jellyfish/_openapi_client/api/recording/get_recordings.py b/jellyfish/_openapi_client/api/recording/get_recordings.py index 99bf969..8855ab9 100644 --- a/jellyfish/_openapi_client/api/recording/get_recordings.py +++ b/jellyfish/_openapi_client/api/recording/get_recordings.py @@ -11,8 +11,6 @@ def _get_kwargs() -> Dict[str, Any]: - pass - return { "method": "get", "url": "/recording", diff --git a/jellyfish/_openapi_client/api/room/add_component.py b/jellyfish/_openapi_client/api/room/add_component.py index 86f492b..376628c 100644 --- a/jellyfish/_openapi_client/api/room/add_component.py +++ b/jellyfish/_openapi_client/api/room/add_component.py @@ -16,8 +16,6 @@ def _get_kwargs( *, json_body: AddComponentJsonBody, ) -> Dict[str, Any]: - pass - json_json_body = json_body.to_dict() return { diff --git a/jellyfish/_openapi_client/api/room/add_peer.py b/jellyfish/_openapi_client/api/room/add_peer.py index 4eb45e3..82a3b18 100644 --- a/jellyfish/_openapi_client/api/room/add_peer.py +++ b/jellyfish/_openapi_client/api/room/add_peer.py @@ -16,8 +16,6 @@ def _get_kwargs( *, json_body: AddPeerJsonBody, ) -> Dict[str, Any]: - pass - json_json_body = json_body.to_dict() return { diff --git a/jellyfish/_openapi_client/api/room/create_room.py b/jellyfish/_openapi_client/api/room/create_room.py index 15da766..c03f2a1 100644 --- a/jellyfish/_openapi_client/api/room/create_room.py +++ b/jellyfish/_openapi_client/api/room/create_room.py @@ -15,8 +15,6 @@ def _get_kwargs( *, json_body: RoomConfig, ) -> Dict[str, Any]: - pass - json_json_body = json_body.to_dict() return { diff --git a/jellyfish/_openapi_client/api/room/delete_component.py b/jellyfish/_openapi_client/api/room/delete_component.py index 766bd09..c5fc775 100644 --- a/jellyfish/_openapi_client/api/room/delete_component.py +++ b/jellyfish/_openapi_client/api/room/delete_component.py @@ -13,8 +13,6 @@ def _get_kwargs( room_id: str, id: str, ) -> Dict[str, Any]: - pass - return { "method": "delete", "url": "/room/{room_id}/component/{id}".format( diff --git a/jellyfish/_openapi_client/api/room/delete_peer.py b/jellyfish/_openapi_client/api/room/delete_peer.py index b428950..e6045df 100644 --- a/jellyfish/_openapi_client/api/room/delete_peer.py +++ b/jellyfish/_openapi_client/api/room/delete_peer.py @@ -13,8 +13,6 @@ def _get_kwargs( room_id: str, id: str, ) -> Dict[str, Any]: - pass - return { "method": "delete", "url": "/room/{room_id}/peer/{id}".format( diff --git a/jellyfish/_openapi_client/api/room/delete_room.py b/jellyfish/_openapi_client/api/room/delete_room.py index e2554df..1ccbcd6 100644 --- a/jellyfish/_openapi_client/api/room/delete_room.py +++ b/jellyfish/_openapi_client/api/room/delete_room.py @@ -12,8 +12,6 @@ def _get_kwargs( room_id: str, ) -> Dict[str, Any]: - pass - return { "method": "delete", "url": "/room/{room_id}".format( diff --git a/jellyfish/_openapi_client/api/room/get_all_rooms.py b/jellyfish/_openapi_client/api/room/get_all_rooms.py index 9664c25..149daf5 100644 --- a/jellyfish/_openapi_client/api/room/get_all_rooms.py +++ b/jellyfish/_openapi_client/api/room/get_all_rooms.py @@ -11,8 +11,6 @@ def _get_kwargs() -> Dict[str, Any]: - pass - return { "method": "get", "url": "/room", diff --git a/jellyfish/_openapi_client/api/room/get_room.py b/jellyfish/_openapi_client/api/room/get_room.py index 95ed166..f6a60ba 100644 --- a/jellyfish/_openapi_client/api/room/get_room.py +++ b/jellyfish/_openapi_client/api/room/get_room.py @@ -13,8 +13,6 @@ def _get_kwargs( room_id: str, ) -> Dict[str, Any]: - pass - return { "method": "get", "url": "/room/{room_id}".format( diff --git a/jellyfish/_openapi_client/models/__init__.py b/jellyfish/_openapi_client/models/__init__.py index 73393a8..2b23d0b 100644 --- a/jellyfish/_openapi_client/models/__init__.py +++ b/jellyfish/_openapi_client/models/__init__.py @@ -14,7 +14,6 @@ from .component_properties_rtsp import ComponentPropertiesRTSP from .component_rtsp import ComponentRTSP from .error import Error -from .hls_skip import HlsSkip from .peer import Peer from .peer_details_response import PeerDetailsResponse from .peer_details_response_data import PeerDetailsResponseData @@ -46,7 +45,6 @@ "ComponentPropertiesRTSP", "ComponentRTSP", "Error", - "HlsSkip", "Peer", "PeerDetailsResponse", "PeerDetailsResponseData", diff --git a/jellyfish/_openapi_client/models/hls_skip.py b/jellyfish/_openapi_client/models/hls_skip.py deleted file mode 100644 index 8cae45a..0000000 --- a/jellyfish/_openapi_client/models/hls_skip.py +++ /dev/null @@ -1,8 +0,0 @@ -from enum import Enum - - -class HlsSkip(str, Enum): - YES = "YES" - - def __str__(self) -> str: - return str(self.value) diff --git a/poetry.lock b/poetry.lock index 9ba6dc6..5f3f30e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -99,21 +99,6 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib- tests = ["attrs[tests-no-zope]", "zope-interface"] tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -[[package]] -name = "autoflake" -version = "2.2.1" -description = "Removes unused imports and unused variables" -optional = false -python-versions = ">=3.8" -files = [ - {file = "autoflake-2.2.1-py3-none-any.whl", hash = "sha256:265cde0a43c1f44ecfb4f30d95b0437796759d07be7706a2f70e4719234c0f79"}, - {file = "autoflake-2.2.1.tar.gz", hash = "sha256:62b7b6449a692c3c9b0c916919bbc21648da7281e8506bcf8d3f8280e431ebc1"}, -] - -[package.dependencies] -pyflakes = ">=3.0.0" -tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} - [[package]] name = "betterproto" version = "2.0.0b6" @@ -908,28 +893,27 @@ files = [ [[package]] name = "openapi-python-client" -version = "0.15.2" +version = "0.16.0" description = "Generate modern Python clients from OpenAPI" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "openapi_python_client-0.15.2-py3-none-any.whl", hash = "sha256:240ff6e571eecd81758410cb743c24b6cabc4d30a3fd79cd886feeb8960610c5"}, - {file = "openapi_python_client-0.15.2.tar.gz", hash = "sha256:a0ff88cd142f907277c333fa4e3bb9461ebfd8e58bad1bbccdd8f14dc3c311e7"}, + {file = "openapi_python_client-0.16.0-py3-none-any.whl", hash = "sha256:2250a718703f99d6e55ff1b6b0bb7bb37f8d6424343d0f86a03d420869860578"}, + {file = "openapi_python_client-0.16.0.tar.gz", hash = "sha256:c1b76d97d1276462445cded66b8e0c9095fa11002f695e5dcc212b45b8bfee9c"}, ] [package.dependencies] attrs = ">=21.3.0" -autoflake = ">=1.4,<3.0.0" -black = ">=23" colorama = {version = ">=0.4.3,<0.5.0", markers = "sys_platform == \"win32\""} httpx = ">=0.20.0,<0.26.0" -isort = ">=5.0.5,<6.0.0" jinja2 = ">=3.0.0,<4.0.0" pydantic = ">=2.1.1,<3.0.0" python-dateutil = ">=2.8.1,<3.0.0" PyYAML = ">=6.0,<7.0" +ruff = ">=0.1.2,<0.2.0" shellingham = ">=1.3.2,<2.0.0" typer = ">0.6,<0.10" +typing-extensions = ">=4.8.0,<5.0.0" [[package]] name = "packaging" @@ -1139,17 +1123,6 @@ files = [ [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" -[[package]] -name = "pyflakes" -version = "3.1.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, -] - [[package]] name = "pygments" version = "2.17.2" @@ -1745,4 +1718,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "ba451508068251b74f4d0db73ad670e8fd050507b300a3b4605fde3923086696" +content-hash = "f833ecf733e2dab5f3e6d3723747ef8bce92fe552917110df8137850bb9e0169" diff --git a/test_commands.py b/poetry_scripts.py similarity index 84% rename from test_commands.py rename to poetry_scripts.py index 402ec55..578f3ad 100644 --- a/test_commands.py +++ b/poetry_scripts.py @@ -1,9 +1,7 @@ import os +import shutil import sys from pathlib import Path -import shutil -import pdoc as p -from pdoc import render def check_exit_code(command): @@ -55,3 +53,11 @@ def generate_docs(): # ...and rename the .html files to .md so that mkdocs picks them up! for f in out.glob("**/*.html"): f.rename(f.with_suffix(".md")) + + +def generate_client(): + check_exit_code( + "openapi-python-client generate\ + --url https://raw.githubusercontent.com/jellyfish-dev/jellyfish/main/openapi.yaml \ + --config openapi-python-client-config.yaml" + ) diff --git a/pyproject.toml b/pyproject.toml index e66854f..5d8de87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,8 +24,8 @@ black = "^23.10.0" pdoc = "^14.1.0" mkdocs = "^1.5.3" mike = "^2.0.0" -openapi-python-client = "^0.15.2" -ruff = "^0.1.6" +openapi-python-client = "^0.16.0" +ruff = "^0.1.7" [tool.poetry.group.test.dependencies] pytest = "^7.4.2" @@ -38,8 +38,14 @@ requires = ["poetry-core>=1.6.0"] build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] -ci_test = "test_commands:run_tests" -format = "test_commands:run_formatter" -check_format = "test_commands:check_format" -lint = "test_commands:run_linter" -generate_docs = "test_commands:generate_docs" +ci_test = "poetry_scripts:run_tests" +format = "poetry_scripts:run_formatter" +check_format = "poetry_scripts:check_format" +lint = "poetry_scripts:run_linter" +generate_docs = "poetry_scripts:generate_docs" +generate_client = "poetry_scripts:generate_client" + +[tool.ruff] +select = ["F", "I"] +line-length = 120 +include = ["pyproject.toml", "jellyfish/_openapi_client/**/*.py"] From 14051eaaca60818aaa7ba58264eeb4acec8b6b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Thu, 14 Dec 2023 15:05:45 +0100 Subject: [PATCH 3/9] Ruff --- README.md | 14 +- generate_client.sh | 16 - jellyfish/__init__.py | 10 + .../api/hls/get_hls_content.py | 12 +- jellyfish/_openapi_client/client.py | 4 +- .../models/add_component_json_body.py | 25 +- .../models/add_peer_json_body.py | 8 +- .../models/component_details_response.py | 11 +- .../_openapi_client/models/component_file.py | 9 +- .../_openapi_client/models/component_hls.py | 11 +- .../models/component_options_file.py | 8 +- .../models/component_options_hls.py | 21 +- .../models/component_options_rtsp.py | 17 +- .../models/component_properties_hls.py | 20 +- .../_openapi_client/models/component_rtsp.py | 11 +- jellyfish/_openapi_client/models/error.py | 7 +- jellyfish/_openapi_client/models/peer.py | 11 +- .../models/peer_details_response.py | 7 +- .../models/peer_details_response_data.py | 8 +- .../models/peer_options_web_rtc.py | 7 +- .../models/recording_list_response.py | 7 +- jellyfish/_openapi_client/models/room.py | 13 +- .../_openapi_client/models/room_config.py | 12 +- .../models/room_create_details_response.py | 11 +- .../room_create_details_response_data.py | 10 +- .../models/room_details_response.py | 7 +- .../models/rooms_listing_response.py | 7 +- .../_openapi_client/models/s3_credentials.py | 9 +- .../models/subscription_config.py | 7 +- jellyfish/_recording_api.py | 6 +- jellyfish/_room_api.py | 34 +- jellyfish/_ws_notifier.py | 8 +- jellyfish/events/__init__.py | 13 +- .../events/_protos/jellyfish/__init__.py | 36 +- openapi.yaml | 977 ------------------ poetry.lock | 4 +- poetry_scripts.py | 12 +- pylintrc | 631 ----------- pyproject.toml | 17 +- templates/model.py.jinja | 203 ++++ templates/partial_header.mustache | 17 - tests/support/peer_socket.py | 4 +- tests/support/protos/jellyfish/__init__.py | 8 +- tests/support/webhook_notifier.py | 3 +- tests/test_notifier.py | 40 +- tests/test_recording_api.py | 4 +- tests/test_room_api.py | 78 +- 47 files changed, 433 insertions(+), 1982 deletions(-) delete mode 100755 generate_client.sh delete mode 100644 openapi.yaml delete mode 100644 pylintrc create mode 100644 templates/model.py.jinja delete mode 100644 templates/partial_header.mustache diff --git a/README.md b/README.md index 67e61b6..d70fb6c 100644 --- a/README.md +++ b/README.md @@ -26,27 +26,27 @@ Create a `RoomApi` instance, providing the jellyfish server address and api toke ```python from jellyfish import RoomApi -room_api = RoomApi(server_address='localhost:5002', server_api_token='development') +room_api = RoomApi(server_address="localhost:5002", server_api_token="development") ``` You can use it to interact with Jellyfish, manage rooms, peers and components ```python # Create a room -jellyfish_address, room = room_api.create_room(video_codec='h264') -# 'localhost:5002', Room(components=[], config=RoomConfig(max_peers=None, video_codec='h264'), id='5a099a31-0eb2-4c28-84af-a1ec55c228af', peers=[])) +jellyfish_address, room = room_api.create_room(video_codec="h264", webhook_url="http://localhost:5000/webhook") +# '127.0.0.1:5002', Room(components=[], config=RoomConfig(max_peers=None, video_codec=, webhook_url='http://localhost:5000/webhook'), id='1d905478-ccfc-44d6-a6e7-8ccb1b38d955', peers=[]) # Add peer to the room from jellyfish import PeerOptionsWebRTC peer_token, peer_webrtc = room_api.add_peer(room.id, options=PeerOptionsWebRTC()) -# 'AgDYfrCSigFiAA', Peer(id='2869fb5', status=, type='webrtc') +# 'M8TUGhj-L11KpyG-2zBPIo', Peer(id='b1232c7e-c969-4450-acdf-ea24f3cdd7f6', status=, type='webrtc') # Add component to the room from jellyfish import ComponentOptionsHLS component_hls = room_api.add_component(room.id, options=ComponentOptionsHLS()) -# Component(actual_instance=ComponentHLS(id='c0dfab50-cafd-438d-985e-7b8f97ae55e3', metadata=ComponentMetadataHLS(low_latency=False, playable=False), type='hls')) +# ComponentHLS(id='5f062447-a9f7-45ed-8d1b-511f77dc78ae', properties=ComponentPropertiesHLS(low_latency=False, persistent=False, playable=False, subscribe_mode=, target_window_duration=None), type='hls') ``` #### Notifier @@ -96,14 +96,14 @@ You can test the SDK by running poetry run ci_test ``` -## Format&Lint +## Format & Lint You can format code by running ```console poetry run format ``` You can check linter by running -``` +```console poetry run lint ``` diff --git a/generate_client.sh b/generate_client.sh deleted file mode 100755 index 6df6d12..0000000 --- a/generate_client.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -TMP_DIR="openapi_client_generated" -PACKAGE_NAME="_openapi_client" - -openapi-generator-cli generate \ - -i https://raw.githubusercontent.com/jellyfish-dev/jellyfish/main/openapi.yaml \ - -g python \ - -o $TMP_DIR \ - -t templates \ - --package-name jellyfish.$PACKAGE_NAME \ - --global-property apis,models,modelTests=false,apiTests=false,modelDocs=false,apiDocs=false,supportingFiles \ - --additional-properties useOneOfDiscriminatorLookup=true && -rm -rf jellyfish/$PACKAGE_NAME -mv $TMP_DIR/jellyfish/$PACKAGE_NAME jellyfish/$PACKAGE_NAME -rm -rf $TMP_DIR diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index 6029d26..4c3c2ba 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -13,9 +13,13 @@ ComponentOptionsHLS, ComponentOptionsHLSSubscribeMode, ComponentOptionsRTSP, + ComponentPropertiesHLS, + ComponentPropertiesHLSSubscribeMode, + ComponentPropertiesRTSP, ComponentRTSP, Peer, PeerOptionsWebRTC, + PeerStatus, Room, RoomConfig, RoomConfigVideoCodec, @@ -28,13 +32,19 @@ from jellyfish._ws_notifier import Notifier __all__ = [ + "ComponentPropertiesHLSSubscribeMode", + "RoomConfigVideoCodec", + "ComponentPropertiesRTSP", "RoomApi", "RecordingApi", "Notifier", "receive_json", "Room", "Peer", + "PeerStatus", "ComponentHLS", + "ComponentPropertiesHLS", + "ComponentOptionsHLSSubscribeMode", "ComponentRTSP", "ComponentOptionsHLS", "RoomConfig", diff --git a/jellyfish/_openapi_client/api/hls/get_hls_content.py b/jellyfish/_openapi_client/api/hls/get_hls_content.py index fd4d641..a064207 100644 --- a/jellyfish/_openapi_client/api/hls/get_hls_content.py +++ b/jellyfish/_openapi_client/api/hls/get_hls_content.py @@ -90,7 +90,8 @@ def sync_detailed( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. + field_hls_skip (Union[Unset, None, str]): Set to "YES" if delta manifest should be + requested Example: True. range_ (Union[Unset, str]): Raises: @@ -134,7 +135,8 @@ def sync( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. + field_hls_skip (Union[Unset, None, str]): Set to "YES" if delta manifest should be + requested Example: True. range_ (Union[Unset, str]): Raises: @@ -173,7 +175,8 @@ async def asyncio_detailed( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. + field_hls_skip (Union[Unset, None, str]): Set to "YES" if delta manifest should be + requested Example: True. range_ (Union[Unset, str]): Raises: @@ -215,7 +218,8 @@ async def asyncio( filename (str): field_hls_msn (Union[Unset, None, int]): Segment sequence number Example: 10. field_hls_part (Union[Unset, None, int]): Partial segment sequence number Example: 10. - field_hls_skip (Union[Unset, None, str]): Is delta manifest requested Example: True. + field_hls_skip (Union[Unset, None, str]): Set to "YES" if delta manifest should be + requested Example: True. range_ (Union[Unset, str]): Raises: diff --git a/jellyfish/_openapi_client/client.py b/jellyfish/_openapi_client/client.py index 0a07559..81c0139 100644 --- a/jellyfish/_openapi_client/client.py +++ b/jellyfish/_openapi_client/client.py @@ -237,9 +237,7 @@ def __exit__(self, *args: Any, **kwargs: Any) -> None: """Exit a context manager for internal httpx.Client (see httpx docs)""" self.get_httpx_client().__exit__(*args, **kwargs) - def set_async_httpx_client( - self, async_client: httpx.AsyncClient - ) -> "AuthenticatedClient": + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": """Manually the underlying httpx.AsyncClient **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. diff --git a/jellyfish/_openapi_client/models/add_component_json_body.py b/jellyfish/_openapi_client/models/add_component_json_body.py index b0206aa..eeac61d 100644 --- a/jellyfish/_openapi_client/models/add_component_json_body.py +++ b/jellyfish/_openapi_client/models/add_component_json_body.py @@ -16,17 +16,14 @@ @_attrs_define class AddComponentJsonBody: - """ - Attributes: - type (str): Component type Example: hls. - options (Union['ComponentOptionsFile', 'ComponentOptionsHLS', 'ComponentOptionsRTSP', Unset]): Component- - specific options - """ + """ """ type: str + """Component type""" options: Union[ "ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset ] = UNSET + """Component-specific options""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -70,17 +67,13 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: def _parse_options( data: object, - ) -> Union[ - "ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset - ]: + ) -> Union["ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset]: if isinstance(data, Unset): return data try: if not isinstance(data, dict): raise TypeError() - componentsschemas_component_options_type_0 = ( - ComponentOptionsHLS.from_dict(data) - ) + componentsschemas_component_options_type_0 = ComponentOptionsHLS.from_dict(data) return componentsschemas_component_options_type_0 except: # noqa: E722 @@ -88,18 +81,14 @@ def _parse_options( try: if not isinstance(data, dict): raise TypeError() - componentsschemas_component_options_type_1 = ( - ComponentOptionsRTSP.from_dict(data) - ) + componentsschemas_component_options_type_1 = ComponentOptionsRTSP.from_dict(data) return componentsschemas_component_options_type_1 except: # noqa: E722 pass if not isinstance(data, dict): raise TypeError() - componentsschemas_component_options_type_2 = ComponentOptionsFile.from_dict( - data - ) + componentsschemas_component_options_type_2 = ComponentOptionsFile.from_dict(data) return componentsschemas_component_options_type_2 diff --git a/jellyfish/_openapi_client/models/add_peer_json_body.py b/jellyfish/_openapi_client/models/add_peer_json_body.py index 325ee74..ef3893a 100644 --- a/jellyfish/_openapi_client/models/add_peer_json_body.py +++ b/jellyfish/_openapi_client/models/add_peer_json_body.py @@ -12,14 +12,12 @@ @_attrs_define class AddPeerJsonBody: - """ - Attributes: - options (PeerOptionsWebRTC): Options specific to the WebRTC peer - type (str): Peer type Example: webrtc. - """ + """ """ options: "PeerOptionsWebRTC" + """Options specific to the WebRTC peer""" type: str + """Peer type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/component_details_response.py b/jellyfish/_openapi_client/models/component_details_response.py index 018b997..1d3332d 100644 --- a/jellyfish/_openapi_client/models/component_details_response.py +++ b/jellyfish/_openapi_client/models/component_details_response.py @@ -14,13 +14,10 @@ @_attrs_define class ComponentDetailsResponse: - """Response containing component details - - Attributes: - data (Union['ComponentFile', 'ComponentHLS', 'ComponentRTSP']): Describes component - """ + """Response containing component details""" data: Union["ComponentFile", "ComponentHLS", "ComponentRTSP"] + """Describes component""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -56,9 +53,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() - def _parse_data( - data: object, - ) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: + def _parse_data(data: object) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: try: if not isinstance(data, dict): raise TypeError() diff --git a/jellyfish/_openapi_client/models/component_file.py b/jellyfish/_openapi_client/models/component_file.py index 4b0a8be..be0427b 100644 --- a/jellyfish/_openapi_client/models/component_file.py +++ b/jellyfish/_openapi_client/models/component_file.py @@ -8,15 +8,12 @@ @_attrs_define class ComponentFile: - """Describes the File component - - Attributes: - id (str): Assigned component ID Example: component-1. - type (str): Component type Example: file. - """ + """Describes the File component""" id: str + """Assigned component ID""" type: str + """Component type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/component_hls.py b/jellyfish/_openapi_client/models/component_hls.py index ac2449e..c7b6647 100644 --- a/jellyfish/_openapi_client/models/component_hls.py +++ b/jellyfish/_openapi_client/models/component_hls.py @@ -12,17 +12,14 @@ @_attrs_define class ComponentHLS: - """Describes the HLS component - - Attributes: - id (str): Assigned component ID Example: component-1. - properties (ComponentPropertiesHLS): Properties specific to the HLS component - type (str): Component type Example: hls. - """ + """Describes the HLS component""" id: str + """Assigned component ID""" properties: "ComponentPropertiesHLS" + """Properties specific to the HLS component""" type: str + """Component type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/component_options_file.py b/jellyfish/_openapi_client/models/component_options_file.py index b707a90..c5f1111 100644 --- a/jellyfish/_openapi_client/models/component_options_file.py +++ b/jellyfish/_openapi_client/models/component_options_file.py @@ -8,14 +8,10 @@ @_attrs_define class ComponentOptionsFile: - """Options specific to the File component - - Attributes: - file_path (str): Path to track file. Must be either OPUS encapsulated in Ogg or raw h264 Example: - /root/video.h264. - """ + """Options specific to the File component""" file_path: str + """Path to track file. Must be either OPUS encapsulated in Ogg or raw h264""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/component_options_hls.py b/jellyfish/_openapi_client/models/component_options_hls.py index 7615311..f0d45eb 100644 --- a/jellyfish/_openapi_client/models/component_options_hls.py +++ b/jellyfish/_openapi_client/models/component_options_hls.py @@ -3,9 +3,7 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -from ..models.component_options_hls_subscribe_mode import ( - ComponentOptionsHLSSubscribeMode, -) +from ..models.component_options_hls_subscribe_mode import ComponentOptionsHLSSubscribeMode from ..types import UNSET, Unset if TYPE_CHECKING: @@ -17,25 +15,20 @@ @_attrs_define class ComponentOptionsHLS: - """Options specific to the HLS component - - Attributes: - low_latency (Union[Unset, bool]): Whether the component should use LL-HLS - persistent (Union[Unset, bool]): Whether the video is stored after end of stream - s3 (Union[Unset, None, S3Credentials]): An AWS S3 credential that will be used to send HLS stream. The stream - will only be uploaded if credentials are provided - subscribe_mode (Union[Unset, ComponentOptionsHLSSubscribeMode]): Whether the HLS component should subscribe to - tracks automatically or manually. Default: ComponentOptionsHLSSubscribeMode.AUTO. - target_window_duration (Union[Unset, None, int]): Duration of stream available for viewer - """ + """Options specific to the HLS component""" low_latency: Union[Unset, bool] = False + """Whether the component should use LL-HLS""" persistent: Union[Unset, bool] = False + """Whether the video is stored after end of stream""" s3: Union[Unset, None, "S3Credentials"] = UNSET + """An AWS S3 credential that will be used to send HLS stream. The stream will only be uploaded if credentials are provided""" subscribe_mode: Union[ Unset, ComponentOptionsHLSSubscribeMode ] = ComponentOptionsHLSSubscribeMode.AUTO + """Whether the HLS component should subscribe to tracks automatically or manually.""" target_window_duration: Union[Unset, None, int] = UNSET + """Duration of stream available for viewer""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/component_options_rtsp.py b/jellyfish/_openapi_client/models/component_options_rtsp.py index 8c536cc..e261edb 100644 --- a/jellyfish/_openapi_client/models/component_options_rtsp.py +++ b/jellyfish/_openapi_client/models/component_options_rtsp.py @@ -10,23 +10,18 @@ @_attrs_define class ComponentOptionsRTSP: - """Options specific to the RTSP component - - Attributes: - source_uri (str): URI of RTSP source stream Example: rtsp://localhost:554/stream. - keep_alive_interval (Union[Unset, int]): Interval (in ms) in which keep-alive RTSP messages will be sent to the - remote stream source Default: 15000. - pierce_nat (Union[Unset, bool]): Whether to attempt to create client-side NAT binding by sending an empty - datagram from client to source, after the completion of RTSP setup Default: True. - reconnect_delay (Union[Unset, int]): Delay (in ms) between successive reconnect attempts Default: 15000. - rtp_port (Union[Unset, int]): Local port RTP stream will be received at Default: 20000. - """ + """Options specific to the RTSP component""" source_uri: str + """URI of RTSP source stream""" keep_alive_interval: Union[Unset, int] = 15000 + """Interval (in ms) in which keep-alive RTSP messages will be sent to the remote stream source""" pierce_nat: Union[Unset, bool] = True + """Whether to attempt to create client-side NAT binding by sending an empty datagram from client to source, after the completion of RTSP setup""" reconnect_delay: Union[Unset, int] = 15000 + """Delay (in ms) between successive reconnect attempts""" rtp_port: Union[Unset, int] = 20000 + """Local port RTP stream will be received at""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/component_properties_hls.py b/jellyfish/_openapi_client/models/component_properties_hls.py index f0bd133..00553d6 100644 --- a/jellyfish/_openapi_client/models/component_properties_hls.py +++ b/jellyfish/_openapi_client/models/component_properties_hls.py @@ -3,31 +3,25 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -from ..models.component_properties_hls_subscribe_mode import ( - ComponentPropertiesHLSSubscribeMode, -) +from ..models.component_properties_hls_subscribe_mode import ComponentPropertiesHLSSubscribeMode T = TypeVar("T", bound="ComponentPropertiesHLS") @_attrs_define class ComponentPropertiesHLS: - """Properties specific to the HLS component - - Attributes: - low_latency (bool): Whether the component uses LL-HLS - persistent (bool): Whether the video is stored after end of stream - playable (bool): Whether the generated HLS playlist is playable - subscribe_mode (ComponentPropertiesHLSSubscribeMode): Whether the HLS component should subscribe to tracks - automatically or manually - target_window_duration (Optional[int]): Duration of stream available for viewer - """ + """Properties specific to the HLS component""" low_latency: bool + """Whether the component uses LL-HLS""" persistent: bool + """Whether the video is stored after end of stream""" playable: bool + """Whether the generated HLS playlist is playable""" subscribe_mode: ComponentPropertiesHLSSubscribeMode + """Whether the HLS component should subscribe to tracks automatically or manually""" target_window_duration: Optional[int] + """Duration of stream available for viewer""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/component_rtsp.py b/jellyfish/_openapi_client/models/component_rtsp.py index a25c60d..70c68a9 100644 --- a/jellyfish/_openapi_client/models/component_rtsp.py +++ b/jellyfish/_openapi_client/models/component_rtsp.py @@ -12,17 +12,14 @@ @_attrs_define class ComponentRTSP: - """Describes the RTSP component - - Attributes: - id (str): Assigned component ID Example: component-1. - properties (ComponentPropertiesRTSP): Properties specific to the RTSP component - type (str): Component type Example: hls. - """ + """Describes the RTSP component""" id: str + """Assigned component ID""" properties: "ComponentPropertiesRTSP" + """Properties specific to the RTSP component""" type: str + """Component type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/error.py b/jellyfish/_openapi_client/models/error.py index 0d246c2..3fa9ea2 100644 --- a/jellyfish/_openapi_client/models/error.py +++ b/jellyfish/_openapi_client/models/error.py @@ -8,13 +8,10 @@ @_attrs_define class Error: - """Error message - - Attributes: - errors (str): Error details Example: Token has expired. - """ + """Error message""" errors: str + """Error details""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/peer.py b/jellyfish/_openapi_client/models/peer.py index 1c3a4ab..b4459ef 100644 --- a/jellyfish/_openapi_client/models/peer.py +++ b/jellyfish/_openapi_client/models/peer.py @@ -10,17 +10,14 @@ @_attrs_define class Peer: - """Describes peer status - - Attributes: - id (str): Assigned peer id Example: peer-1. - status (PeerStatus): Informs about the peer status Example: disconnected. - type (str): Peer type Example: webrtc. - """ + """Describes peer status""" id: str + """Assigned peer id""" status: PeerStatus + """Informs about the peer status""" type: str + """Peer type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/peer_details_response.py b/jellyfish/_openapi_client/models/peer_details_response.py index 34863f3..5a024ad 100644 --- a/jellyfish/_openapi_client/models/peer_details_response.py +++ b/jellyfish/_openapi_client/models/peer_details_response.py @@ -12,13 +12,10 @@ @_attrs_define class PeerDetailsResponse: - """Response containing peer details and their token - - Attributes: - data (PeerDetailsResponseData): - """ + """Response containing peer details and their token""" data: "PeerDetailsResponseData" + """""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/peer_details_response_data.py b/jellyfish/_openapi_client/models/peer_details_response_data.py index 58bb706..92140f9 100644 --- a/jellyfish/_openapi_client/models/peer_details_response_data.py +++ b/jellyfish/_openapi_client/models/peer_details_response_data.py @@ -12,14 +12,12 @@ @_attrs_define class PeerDetailsResponseData: - """ - Attributes: - peer (Peer): Describes peer status - token (str): Token for authorizing websocket connection Example: 5cdac726-57a3-4ecb-b1d5-72a3d62ec242. - """ + """ """ peer: "Peer" + """Describes peer status""" token: str + """Token for authorizing websocket connection""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/peer_options_web_rtc.py b/jellyfish/_openapi_client/models/peer_options_web_rtc.py index c314b96..e1355be 100644 --- a/jellyfish/_openapi_client/models/peer_options_web_rtc.py +++ b/jellyfish/_openapi_client/models/peer_options_web_rtc.py @@ -10,13 +10,10 @@ @_attrs_define class PeerOptionsWebRTC: - """Options specific to the WebRTC peer - - Attributes: - enable_simulcast (Union[Unset, bool]): Enables the peer to use simulcast Default: True. - """ + """Options specific to the WebRTC peer""" enable_simulcast: Union[Unset, bool] = True + """Enables the peer to use simulcast""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/recording_list_response.py b/jellyfish/_openapi_client/models/recording_list_response.py index b48dbf6..716ed4b 100644 --- a/jellyfish/_openapi_client/models/recording_list_response.py +++ b/jellyfish/_openapi_client/models/recording_list_response.py @@ -8,13 +8,10 @@ @_attrs_define class RecordingListResponse: - """Response containing list of all recording - - Attributes: - data (List[str]): - """ + """Response containing list of all recording""" data: List[str] + """None""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/room.py b/jellyfish/_openapi_client/models/room.py index a960829..711f067 100644 --- a/jellyfish/_openapi_client/models/room.py +++ b/jellyfish/_openapi_client/models/room.py @@ -16,19 +16,16 @@ @_attrs_define class Room: - """Description of the room state - - Attributes: - components (List[Union['ComponentFile', 'ComponentHLS', 'ComponentRTSP']]): - config (RoomConfig): Room configuration - id (str): Room ID Example: room-1. - peers (List['Peer']): - """ + """Description of the room state""" components: List[Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]] + """List of all components""" config: "RoomConfig" + """Room configuration""" id: str + """Room ID""" peers: List["Peer"] + """List of all peers""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/room_config.py b/jellyfish/_openapi_client/models/room_config.py index dd4b7d7..5a1aa9c 100644 --- a/jellyfish/_openapi_client/models/room_config.py +++ b/jellyfish/_openapi_client/models/room_config.py @@ -11,18 +11,14 @@ @_attrs_define class RoomConfig: - """Room configuration - - Attributes: - max_peers (Union[Unset, None, int]): Maximum amount of peers allowed into the room Example: 10. - video_codec (Union[Unset, None, RoomConfigVideoCodec]): Enforces video codec for each peer in the room - webhook_url (Union[Unset, None, str]): URL where Jellyfish notifications will be sent Example: - https://backend.address.com/jellyfish-notifications-endpoint. - """ + """Room configuration""" max_peers: Union[Unset, None, int] = UNSET + """Maximum amount of peers allowed into the room""" video_codec: Union[Unset, None, RoomConfigVideoCodec] = UNSET + """Enforces video codec for each peer in the room""" webhook_url: Union[Unset, None, str] = UNSET + """URL where Jellyfish notifications will be sent""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/room_create_details_response.py b/jellyfish/_openapi_client/models/room_create_details_response.py index 5573ee2..207bf33 100644 --- a/jellyfish/_openapi_client/models/room_create_details_response.py +++ b/jellyfish/_openapi_client/models/room_create_details_response.py @@ -12,13 +12,10 @@ @_attrs_define class RoomCreateDetailsResponse: - """Response containing room details - - Attributes: - data (RoomCreateDetailsResponseData): - """ + """Response containing room details""" data: "RoomCreateDetailsResponseData" + """""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -36,9 +33,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: - from ..models.room_create_details_response_data import ( - RoomCreateDetailsResponseData, - ) + from ..models.room_create_details_response_data import RoomCreateDetailsResponseData d = src_dict.copy() data = RoomCreateDetailsResponseData.from_dict(d.pop("data")) diff --git a/jellyfish/_openapi_client/models/room_create_details_response_data.py b/jellyfish/_openapi_client/models/room_create_details_response_data.py index 726f8ab..f5df3d6 100644 --- a/jellyfish/_openapi_client/models/room_create_details_response_data.py +++ b/jellyfish/_openapi_client/models/room_create_details_response_data.py @@ -12,16 +12,12 @@ @_attrs_define class RoomCreateDetailsResponseData: - """ - Attributes: - jellyfish_address (str): Jellyfish instance address where the room was created. This might be different than the - address of Jellyfish where the request was sent only when running a cluster of Jellyfishes. Example: - jellyfish1:5003. - room (Room): Description of the room state - """ + """ """ jellyfish_address: str + """Jellyfish instance address where the room was created. This might be different than the address of Jellyfish where the request was sent only when running a cluster of Jellyfishes.""" room: "Room" + """Description of the room state""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/room_details_response.py b/jellyfish/_openapi_client/models/room_details_response.py index 1bc222b..efc11bd 100644 --- a/jellyfish/_openapi_client/models/room_details_response.py +++ b/jellyfish/_openapi_client/models/room_details_response.py @@ -12,13 +12,10 @@ @_attrs_define class RoomDetailsResponse: - """Response containing room details - - Attributes: - data (Room): Description of the room state - """ + """Response containing room details""" data: "Room" + """Description of the room state""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/rooms_listing_response.py b/jellyfish/_openapi_client/models/rooms_listing_response.py index 30ed582..02d3ef6 100644 --- a/jellyfish/_openapi_client/models/rooms_listing_response.py +++ b/jellyfish/_openapi_client/models/rooms_listing_response.py @@ -12,13 +12,10 @@ @_attrs_define class RoomsListingResponse: - """Response containing list of all rooms - - Attributes: - data (List['Room']): - """ + """Response containing list of all rooms""" data: List["Room"] + """None""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/s3_credentials.py b/jellyfish/_openapi_client/models/s3_credentials.py index 8115093..41292bf 100644 --- a/jellyfish/_openapi_client/models/s3_credentials.py +++ b/jellyfish/_openapi_client/models/s3_credentials.py @@ -11,17 +11,16 @@ class S3Credentials: """An AWS S3 credential that will be used to send HLS stream. The stream will only be uploaded if credentials are provided - Attributes: - access_key_id (str): An AWS access key identifier, linked to your AWS account. - bucket (str): The name of the S3 bucket where your data will be stored. - region (str): The AWS region where your bucket is located. - secret_access_key (str): The secret key that is linked to the Access Key ID. """ access_key_id: str + """An AWS access key identifier, linked to your AWS account.""" bucket: str + """The name of the S3 bucket where your data will be stored.""" region: str + """The AWS region where your bucket is located.""" secret_access_key: str + """The secret key that is linked to the Access Key ID.""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_openapi_client/models/subscription_config.py b/jellyfish/_openapi_client/models/subscription_config.py index 2b04727..8ad49ff 100644 --- a/jellyfish/_openapi_client/models/subscription_config.py +++ b/jellyfish/_openapi_client/models/subscription_config.py @@ -10,13 +10,10 @@ @_attrs_define class SubscriptionConfig: - """Subscription config - - Attributes: - tracks (Union[Unset, List[str]]): List of tracks that hls endpoint will subscribe for - """ + """Subscription config""" tracks: Union[Unset, List[str]] = UNSET + """List of tracks that hls endpoint will subscribe for""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: diff --git a/jellyfish/_recording_api.py b/jellyfish/_recording_api.py index 1fa123a..43466dc 100644 --- a/jellyfish/_recording_api.py +++ b/jellyfish/_recording_api.py @@ -3,7 +3,7 @@ """ from jellyfish._openapi_client import AuthenticatedClient -from jellyfish._openapi_client.api.recording import get_recordings, delete_recording +from jellyfish._openapi_client.api.recording import delete_recording, get_recordings from jellyfish._openapi_client.models import Error @@ -22,9 +22,7 @@ def __init__( """ protocol = "https" if secure else "http" - self._client = AuthenticatedClient( - f"{protocol}://{server_address}", token=server_api_token - ) + self._client = AuthenticatedClient(f"{protocol}://{server_address}", token=server_api_token) def get_list(self) -> list: """Returns a list of available recordings""" diff --git a/jellyfish/_room_api.py b/jellyfish/_room_api.py index c94e63e..f0ba3d5 100644 --- a/jellyfish/_room_api.py +++ b/jellyfish/_room_api.py @@ -5,6 +5,7 @@ from typing import Literal, Union from jellyfish._openapi_client import AuthenticatedClient +from jellyfish._openapi_client.api.hls import subscribe_tracks from jellyfish._openapi_client.api.room import ( add_component, add_peer, @@ -15,21 +16,20 @@ get_all_rooms, get_room, ) - -from jellyfish._openapi_client.api.hls import subscribe_tracks - from jellyfish._openapi_client.models import ( - AddPeerJsonBody, AddComponentJsonBody, - SubscriptionConfig, - Room, - PeerOptionsWebRTC, - RoomConfig, - Peer, + AddPeerJsonBody, + ComponentHLS, ComponentOptionsHLS, ComponentOptionsRTSP, - RoomConfigVideoCodec, + ComponentRTSP, Error, + Peer, + PeerOptionsWebRTC, + Room, + RoomConfig, + RoomConfigVideoCodec, + SubscriptionConfig, ) @@ -49,9 +49,7 @@ def __init__( protocol = "https" if secure else "http" - self._client = AuthenticatedClient( - f"{protocol}://{server_address}", token=server_api_token - ) + self._client = AuthenticatedClient(f"{protocol}://{server_address}", token=server_api_token) def create_room( self, @@ -120,7 +118,7 @@ def delete_peer(self, room_id: str, peer_id: str) -> None: def add_component( self, room_id: str, options: Union[ComponentOptionsHLS, ComponentOptionsRTSP] - ) -> any: + ) -> Union[ComponentHLS, ComponentRTSP]: """Creates component in the room""" if isinstance(options, ComponentOptionsHLS): @@ -128,9 +126,7 @@ def add_component( elif isinstance(options, ComponentOptionsRTSP): component_type = "rtsp" else: - raise ValueError( - "options must be either ComponentOptionsHLS or ComponentOptionsRTSP" - ) + raise ValueError("options must be either ComponentOptionsHLS or ComponentOptionsRTSP") json_body = AddComponentJsonBody(type=component_type, options=options) @@ -146,9 +142,7 @@ def hls_subscribe(self, room_id: str, tracks: list): subscription_config = SubscriptionConfig(tracks=tracks) - return self._request( - subscribe_tracks, room_id=room_id, json_body=subscription_config - ) + return self._request(subscribe_tracks, room_id=room_id, json_body=subscription_config) def _request(self, method, **kwargs): resp = method.sync(client=self._client, **kwargs) diff --git a/jellyfish/_ws_notifier.py b/jellyfish/_ws_notifier.py index b06c4c3..eaf25dc 100644 --- a/jellyfish/_ws_notifier.py +++ b/jellyfish/_ws_notifier.py @@ -86,9 +86,7 @@ async def connect(self): ) if self._metrics_handler: - await self._subscribe_event( - event=ServerMessageEventType.EVENT_TYPE_METRICS - ) + await self._subscribe_event(event=ServerMessageEventType.EVENT_TYPE_METRICS) self._ready = True if self._ready_event: @@ -113,9 +111,7 @@ async def wait_ready(self) -> True: await self._ready_event.wait() async def _authenticate(self): - msg = ServerMessage( - auth_request=ServerMessageAuthRequest(token=self._server_api_token) - ) + msg = ServerMessage(auth_request=ServerMessageAuthRequest(token=self._server_api_token)) await self._websocket.send(bytes(msg)) try: diff --git a/jellyfish/events/__init__.py b/jellyfish/events/__init__.py index 1190d0b..683f9ed 100644 --- a/jellyfish/events/__init__.py +++ b/jellyfish/events/__init__.py @@ -3,13 +3,12 @@ """ # Exported messages -# Private messages from jellyfish.events._protos.jellyfish import ( - ServerMessage, - ServerMessageAuthenticated, - ServerMessageAuthRequest, + ServerMessage, # noqa: F401 + ServerMessageAuthenticated, # noqa: F401 + ServerMessageAuthRequest, # noqa: F401 ServerMessageComponentCrashed, - ServerMessageEventType, + ServerMessageEventType, # noqa: F401 ServerMessageHlsPlayable, ServerMessageMetricsReport, ServerMessagePeerConnected, @@ -18,8 +17,8 @@ ServerMessageRoomCrashed, ServerMessageRoomCreated, ServerMessageRoomDeleted, - ServerMessageSubscribeRequest, - ServerMessageSubscribeResponse, + ServerMessageSubscribeRequest, # noqa: F401 + ServerMessageSubscribeResponse, # noqa: F401 ) __all__ = [ diff --git a/jellyfish/events/_protos/jellyfish/__init__.py b/jellyfish/events/_protos/jellyfish/__init__.py index 7891f60..8f0ee65 100644 --- a/jellyfish/events/_protos/jellyfish/__init__.py +++ b/jellyfish/events/_protos/jellyfish/__init__.py @@ -16,45 +16,27 @@ class ServerMessageEventType(betterproto.Enum): @dataclass(eq=False, repr=False) class ServerMessage(betterproto.Message): - room_crashed: "ServerMessageRoomCrashed" = betterproto.message_field( - 1, group="content" - ) - peer_connected: "ServerMessagePeerConnected" = betterproto.message_field( - 2, group="content" - ) + room_crashed: "ServerMessageRoomCrashed" = betterproto.message_field(1, group="content") + peer_connected: "ServerMessagePeerConnected" = betterproto.message_field(2, group="content") peer_disconnected: "ServerMessagePeerDisconnected" = betterproto.message_field( 3, group="content" ) - peer_crashed: "ServerMessagePeerCrashed" = betterproto.message_field( - 4, group="content" - ) + peer_crashed: "ServerMessagePeerCrashed" = betterproto.message_field(4, group="content") component_crashed: "ServerMessageComponentCrashed" = betterproto.message_field( 5, group="content" ) - authenticated: "ServerMessageAuthenticated" = betterproto.message_field( - 6, group="content" - ) - auth_request: "ServerMessageAuthRequest" = betterproto.message_field( - 7, group="content" - ) + authenticated: "ServerMessageAuthenticated" = betterproto.message_field(6, group="content") + auth_request: "ServerMessageAuthRequest" = betterproto.message_field(7, group="content") subscribe_request: "ServerMessageSubscribeRequest" = betterproto.message_field( 8, group="content" ) subscribe_response: "ServerMessageSubscribeResponse" = betterproto.message_field( 9, group="content" ) - room_created: "ServerMessageRoomCreated" = betterproto.message_field( - 10, group="content" - ) - room_deleted: "ServerMessageRoomDeleted" = betterproto.message_field( - 11, group="content" - ) - metrics_report: "ServerMessageMetricsReport" = betterproto.message_field( - 12, group="content" - ) - hls_playable: "ServerMessageHlsPlayable" = betterproto.message_field( - 13, group="content" - ) + room_created: "ServerMessageRoomCreated" = betterproto.message_field(10, group="content") + room_deleted: "ServerMessageRoomDeleted" = betterproto.message_field(11, group="content") + metrics_report: "ServerMessageMetricsReport" = betterproto.message_field(12, group="content") + hls_playable: "ServerMessageHlsPlayable" = betterproto.message_field(13, group="content") @dataclass(eq=False, repr=False) diff --git a/openapi.yaml b/openapi.yaml deleted file mode 100644 index 4bd074c..0000000 --- a/openapi.yaml +++ /dev/null @@ -1,977 +0,0 @@ -# This file has been generated using OpenApiSpex. Do not edit manually! -# Run `mix api.spec` to regenerate - ---- -components: - responses: {} - schemas: - PeerStatus: - description: Informs about the peer status - enum: - - connected - - disconnected - example: disconnected - title: PeerStatus - type: string - x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Status - RoomDetailsResponse: - description: Response containing room details - properties: - data: - $ref: '#/components/schemas/Room' - required: - - data - title: RoomDetailsResponse - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.RoomDetailsResponse - ComponentOptionsRTSP: - description: Options specific to the RTSP component - properties: - keepAliveInterval: - default: 15000 - description: Interval (in ms) in which keep-alive RTSP messages will be sent to the remote stream source - minimum: 0 - type: integer - pierceNat: - default: true - description: Whether to attempt to create client-side NAT binding by sending an empty datagram from client to source, after the completion of RTSP setup - type: boolean - reconnectDelay: - default: 15000 - description: Delay (in ms) between successive reconnect attempts - minimum: 0 - type: integer - rtpPort: - default: 20000 - description: Local port RTP stream will be received at - maximum: 65535 - minimum: 1 - type: integer - sourceUri: - description: URI of RTSP source stream - example: rtsp://localhost:554/stream - type: string - required: - - sourceUri - title: ComponentOptionsRTSP - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.RTSP.Options - ComponentPropertiesHLS: - description: Properties specific to the HLS component - properties: - lowLatency: - description: Whether the component uses LL-HLS - type: boolean - persistent: - description: Whether the video is stored after end of stream - type: boolean - playable: - description: Whether the generated HLS playlist is playable - type: boolean - subscribeMode: - description: Whether the HLS component should subscribe to tracks automatically or manually - enum: - - auto - - manual - type: string - targetWindowDuration: - description: Duration of stream available for viewer - nullable: true - type: integer - required: - - playable - - lowLatency - - persistent - - targetWindowDuration - - subscribeMode - title: ComponentPropertiesHLS - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS.Properties - Room: - description: Description of the room state - properties: - components: - items: - $ref: '#/components/schemas/Component' - type: array - config: - $ref: '#/components/schemas/RoomConfig' - id: - description: Room ID - example: room-1 - type: string - peers: - items: - $ref: '#/components/schemas/Peer' - type: array - required: - - id - - config - - components - - peers - title: Room - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Room - Component: - description: Describes component - discriminator: - mapping: - file: '#/components/schemas/ComponentFile' - hls: '#/components/schemas/ComponentHLS' - rtsp: '#/components/schemas/ComponentRTSP' - propertyName: type - oneOf: - - $ref: '#/components/schemas/ComponentHLS' - - $ref: '#/components/schemas/ComponentRTSP' - - $ref: '#/components/schemas/ComponentFile' - title: Component - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component - PeerOptionsWebRTC: - description: Options specific to the WebRTC peer - properties: - enableSimulcast: - default: true - description: Enables the peer to use simulcast - type: boolean - title: PeerOptionsWebRTC - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.WebRTC - ComponentHLS: - description: Describes the HLS component - properties: - id: - description: Assigned component ID - example: component-1 - type: string - properties: - $ref: '#/components/schemas/ComponentPropertiesHLS' - type: - description: Component type - example: hls - type: string - required: - - id - - type - - properties - title: ComponentHLS - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS - HlsSkip: - description: Is delta manifest requested - enum: - - "YES" - example: "YES" - nullable: true - title: HlsSkip - type: string - x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Params.HlsSkip - ComponentFile: - description: Describes the File component - properties: - id: - description: Assigned component ID - example: component-1 - type: string - type: - description: Component type - example: file - type: string - required: - - id - - type - title: ComponentFile - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.File - SubscriptionConfig: - description: Subscription config - properties: - tracks: - description: List of tracks that hls endpoint will subscribe for - items: - $ref: '#/components/schemas/Track' - type: array - title: SubscriptionConfig - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Subscription.Tracks - HlsMsn: - description: Segment sequence number - example: 10 - minimum: 0 - nullable: true - title: HlsMsn - type: integer - x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Params.HlsMsn - ComponentRTSP: - description: Describes the RTSP component - properties: - id: - description: Assigned component ID - example: component-1 - type: string - properties: - $ref: '#/components/schemas/ComponentPropertiesRTSP' - type: - description: Component type - example: hls - type: string - required: - - id - - type - - properties - title: ComponentRTSP - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.RTSP - HlsPart: - description: Partial segment sequence number - example: 10 - minimum: 0 - nullable: true - title: HlsPart - type: integer - x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Params.HlsPart - ComponentDetailsResponse: - description: Response containing component details - properties: - data: - $ref: '#/components/schemas/Component' - required: - - data - title: ComponentDetailsResponse - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.ComponentDetailsResponse - ComponentOptionsHLS: - description: Options specific to the HLS component - properties: - lowLatency: - default: false - description: Whether the component should use LL-HLS - type: boolean - persistent: - default: false - description: Whether the video is stored after end of stream - type: boolean - s3: - description: Credentials to AWS S3 bucket. - nullable: true - oneOf: - - $ref: '#/components/schemas/S3Credentials' - type: object - subscribeMode: - default: auto - description: Whether the HLS component should subscribe to tracks automatically or manually. - enum: - - auto - - manual - type: string - targetWindowDuration: - description: Duration of stream available for viewer - nullable: true - type: integer - title: ComponentOptionsHLS - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS.Options - S3Credentials: - description: An AWS S3 credential that will be used to send HLS stream. The stream will only be uploaded if credentials are provided - properties: - accessKeyId: - description: An AWS access key identifier, linked to your AWS account. - type: string - bucket: - description: The name of the S3 bucket where your data will be stored. - type: string - region: - description: The AWS region where your bucket is located. - type: string - secretAccessKey: - description: The secret key that is linked to the Access Key ID. - type: string - required: - - accessKeyId - - secretAccessKey - - region - - bucket - title: S3Credentials - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.HLS.S3 - RecordingListResponse: - description: Response containing list of all recording - properties: - data: - items: - type: string - type: array - required: - - data - title: RecordingListResponse - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.RecordingListResponse - ComponentOptions: - description: Component-specific options - oneOf: - - $ref: '#/components/schemas/ComponentOptionsHLS' - - $ref: '#/components/schemas/ComponentOptionsRTSP' - - $ref: '#/components/schemas/ComponentOptionsFile' - title: ComponentOptions - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.Options - Track: - description: Track id - example: track-1 - title: Track - type: string - x-struct: Elixir.JellyfishWeb.ApiSpec.Subscription.Track - ComponentPropertiesRTSP: - description: Properties specific to the RTSP component - properties: {} - title: ComponentPropertiesRTSP - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.RTSP.Properties - PeerOptions: - description: Peer-specific options - oneOf: - - $ref: '#/components/schemas/PeerOptionsWebRTC' - title: PeerOptions - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Options - Peer: - description: Describes peer status - properties: - id: - description: Assigned peer id - example: peer-1 - type: string - status: - $ref: '#/components/schemas/PeerStatus' - type: - $ref: '#/components/schemas/PeerType' - required: - - id - - type - - status - title: Peer - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Peer - ComponentType: - description: Component type - example: hls - title: ComponentType - type: string - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.Type - AuthToken: - description: Token for authorizing websocket connection - example: 5cdac726-57a3-4ecb-b1d5-72a3d62ec242 - title: AuthToken - type: string - x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Token - RoomsListingResponse: - description: Response containing list of all rooms - properties: - data: - items: - $ref: '#/components/schemas/Room' - type: array - required: - - data - title: RoomsListingResponse - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.RoomsListingResponse - PeerDetailsResponse: - description: Response containing peer details and their token - properties: - data: - properties: - peer: - $ref: '#/components/schemas/Peer' - token: - $ref: '#/components/schemas/AuthToken' - required: - - peer - - token - type: object - required: - - data - title: PeerDetailsResponse - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.PeerDetailsResponse - HlsResponse: - description: Requested file - title: HlsResponse - type: string - x-struct: Elixir.JellyfishWeb.ApiSpec.HLS.Response - PeerType: - description: Peer type - example: webrtc - title: PeerType - type: string - x-struct: Elixir.JellyfishWeb.ApiSpec.Peer.Type - RoomCreateDetailsResponse: - description: Response containing room details - properties: - data: - properties: - jellyfish_address: - description: Jellyfish instance address where the room was created. This might be different than the address of Jellyfish where the request was sent only when running a cluster of Jellyfishes. - example: jellyfish1:5003 - type: string - room: - $ref: '#/components/schemas/Room' - required: - - room - - jellyfish_address - type: object - required: - - data - title: RoomCreateDetailsResponse - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.RoomCreateDetailsResponse - ComponentOptionsFile: - description: Options specific to the File component - properties: - filePath: - description: Path to track file. Must be either OPUS encapsulated in Ogg or raw h264 - example: /root/video.h264 - type: string - required: - - filePath - title: ComponentOptionsFile - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Component.File.Options - Error: - description: Error message - properties: - errors: - description: Error details - example: Token has expired - type: string - required: - - errors - title: Error - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Error - RoomConfig: - description: Room configuration - properties: - maxPeers: - description: Maximum amount of peers allowed into the room - example: 10 - minimum: 1 - nullable: true - type: integer - videoCodec: - description: Enforces video codec for each peer in the room - enum: - - h264 - - vp8 - nullable: true - type: string - webhookUrl: - description: URL where Jellyfish notifications will be sent - example: https://backend.address.com/jellyfish-notifications-endpoint - nullable: true - type: string - title: RoomConfig - type: object - x-struct: Elixir.JellyfishWeb.ApiSpec.Room.Config - securitySchemes: - authorization: - scheme: bearer - type: http -info: - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0 - title: Jellyfish Media Server - version: 0.2.0 -openapi: 3.0.0 -paths: - /hls/{room_id}/subscribe: - post: - callbacks: {} - operationId: subscribe_tracks - parameters: - - description: Room ID - in: path - name: room_id - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/SubscriptionConfig' - description: Subscribe configuration - required: false - responses: - '201': - description: Tracks succesfully added. - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Invalid request structure - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Room doesn't exist - summary: Subscribe hls component for tracks - tags: - - hls - /hls/{room_id}/{filename}: - get: - callbacks: {} - operationId: getHlsContent - parameters: - - description: Room id - in: path - name: room_id - required: true - schema: - type: string - - description: Name of the file - in: path - name: filename - required: true - schema: - type: string - - description: Byte range of partial segment - in: header - name: range - required: false - schema: - type: string - - description: Segment sequence number - in: query - name: _HLS_msn - required: false - schema: - $ref: '#/components/schemas/HlsMsn' - - description: Partial segment sequence number - in: query - name: _HLS_part - required: false - schema: - $ref: '#/components/schemas/HlsPart' - - description: Is delta manifest requested - in: query - name: _HLS_skip - required: false - schema: - $ref: '#/components/schemas/HlsSkip' - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/HlsResponse' - description: File was found - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Invalid filename - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: File not found - summary: Retrieve HLS Content - tags: - - hls - /recording: - get: - callbacks: {} - operationId: get_recordings - parameters: [] - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/RecordingListResponse' - description: Success - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unable to obtain recordings - summary: Lists all available recordings - tags: - - recording - /recording/{recording_id}: - delete: - callbacks: {} - operationId: delete_recording - parameters: - - description: Recording id - in: path - name: recording_id - required: true - schema: - type: string - responses: - '204': - description: Successfully deleted recording - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Invalid recording - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Recording doesn't exist - summary: Deletes the recording - tags: - - recording - /recording/{recording_id}/{filename}: - get: - callbacks: {} - operationId: getRecordingContent - parameters: - - description: Recording id - in: path - name: recording_id - required: true - schema: - type: string - - description: Name of the file - in: path - name: filename - required: true - schema: - type: string - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/HlsResponse' - description: File was found - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Invalid request - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: File not found - summary: Retrieve Recording (HLS) Content - tags: - - recording - /room: - get: - callbacks: {} - operationId: get_all_rooms - parameters: [] - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/RoomsListingResponse' - description: Success - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - summary: Show information about all rooms - tags: - - room - post: - callbacks: {} - operationId: create_room - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/RoomConfig' - description: Room configuration - required: false - responses: - '201': - content: - application/json: - schema: - $ref: '#/components/schemas/RoomCreateDetailsResponse' - description: Room successfully created - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Invalid request structure - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - summary: Creates a room - tags: - - room - /room/{room_id}: - delete: - callbacks: {} - operationId: delete_room - parameters: - - description: Room id - in: path - name: room_id - required: true - schema: - type: string - responses: - '204': - description: Successfully deleted room - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Room doesn't exist - summary: Delete the room - tags: - - room - get: - callbacks: {} - operationId: get_room - parameters: - - description: Room ID - in: path - name: room_id - required: true - schema: - type: string - responses: - '200': - content: - application/json: - schema: - $ref: '#/components/schemas/RoomDetailsResponse' - description: Success - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Room doesn't exist - summary: Shows information about the room - tags: - - room - /room/{room_id}/component: - post: - callbacks: {} - operationId: add_component - parameters: - - description: Room ID - in: path - name: room_id - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - properties: - options: - $ref: '#/components/schemas/ComponentOptions' - type: - $ref: '#/components/schemas/ComponentType' - required: - - type - type: object - description: Component config - required: false - responses: - '201': - content: - application/json: - schema: - $ref: '#/components/schemas/ComponentDetailsResponse' - description: Successfully added component - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Invalid request - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Room doesn't exist - summary: Creates the component and adds it to the room - tags: - - room - /room/{room_id}/component/{id}: - delete: - callbacks: {} - operationId: delete_component - parameters: - - description: Room ID - in: path - name: room_id - required: true - schema: - type: string - - description: Component ID - in: path - name: id - required: true - schema: - type: string - responses: - '204': - description: Successfully deleted - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Either component or the room doesn't exist - summary: Delete the component from the room - tags: - - room - /room/{room_id}/peer: - post: - callbacks: {} - operationId: add_peer - parameters: - - description: Room id - in: path - name: room_id - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - properties: - options: - $ref: '#/components/schemas/PeerOptions' - type: - $ref: '#/components/schemas/PeerType' - required: - - type - - options - type: object - description: Peer specification - required: false - responses: - '201': - content: - application/json: - schema: - $ref: '#/components/schemas/PeerDetailsResponse' - description: Peer successfully created - '400': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Invalid request body structure - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Room doesn't exist - '503': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Peer limit has been reached - summary: Create peer - tags: - - room - /room/{room_id}/peer/{id}: - delete: - callbacks: {} - operationId: delete_peer - parameters: - - description: Room ID - in: path - name: room_id - required: true - schema: - type: string - - description: Peer id - in: path - name: id - required: true - schema: - type: string - responses: - '204': - description: Peer successfully deleted - '401': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Unauthorized - '404': - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Room ID or Peer ID references a resource that doesn't exist - summary: Delete peer - tags: - - room -security: - - authorization: [] -servers: [] -tags: [] \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 5f3f30e..3398e21 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aenum" @@ -1718,4 +1718,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "f833ecf733e2dab5f3e6d3723747ef8bce92fe552917110df8137850bb9e0169" +content-hash = "50a2fb308d1136e379d26b0057912c8343c833f74a351b58257be569c0b10a63" diff --git a/poetry_scripts.py b/poetry_scripts.py index 578f3ad..7e190c3 100644 --- a/poetry_scripts.py +++ b/poetry_scripts.py @@ -19,16 +19,16 @@ def run_tests(): check_exit_code("docker compose -f docker-compose-test.yaml down") -def check_format(): - check_exit_code("black --check .") - - def run_formatter(): - check_exit_code("black .") + check_exit_code("ruff format .") def run_linter(): - check_exit_code("poetry run pylint --rcfile=pylintrc jellyfish tests") + check_exit_code("ruff check .") + + +def run_linter_fix(): + check_exit_code("ruff check . --fix") def generate_docs(): diff --git a/pylintrc b/pylintrc deleted file mode 100644 index 33374d2..0000000 --- a/pylintrc +++ /dev/null @@ -1,631 +0,0 @@ -[MAIN] - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Clear in-memory caches upon conclusion of linting. Useful if running pylint -# in a server-like mode. -clear-cache-post-run=no - -# Load and enable all available extensions. Use --list-extensions to see a list -# all available extensions. -#enable-all-extensions= - -# In error mode, messages with a category besides ERROR or FATAL are -# suppressed, and no reports are done by default. Error mode is compatible with -# disabling specific errors. -#errors-only= - -# Always return a 0 (non-error) status code, even if lint errors are found. -# This is primarily useful in continuous integration scripts. -#exit-zero= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. -extension-pkg-allow-list= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. (This is an alternative name to extension-pkg-allow-list -# for backward compatibility.) -extension-pkg-whitelist= - -# Return non-zero exit code if any of these messages/categories are detected, -# even if score is above --fail-under value. Syntax same as enable. Messages -# specified are enabled, while categories only check already-enabled messages. -fail-on= - -# Specify a score threshold under which the program will exit with error. -fail-under=10 - -# Interpret the stdin as a python script, whose filename needs to be passed as -# the module_or_package argument. -#from-stdin= - -# Files or directories to be skipped. They should be base names, not paths. -ignore=CVS - -# Add files or directories matching the regular expressions patterns to the -# ignore-list. The regex matches against paths and can be in Posix or Windows -# format. Because '\\' represents the directory delimiter on Windows systems, -# it can't be used as an escape character. -ignore-paths=jellyfish/_openapi_client/,jellyfish/events/_protos/,tests/support/protos - -# Files or directories matching the regular expression patterns are skipped. -# The regex matches against base names, not paths. The default value ignores -# Emacs file locks -ignore-patterns=^\.# - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis). It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the -# number of processors available to use, and will cap the count on Windows to -# avoid hangs. -jobs=1 - -# Control the amount of potential inferred values when inferring a single -# object. This can help the performance when dealing with large functions or -# complex, nested conditions. -limit-inference-results=100 - -# List of plugins (as comma separated values of python module names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Minimum Python version to use for version dependent checks. Will default to -# the version used to run pylint. -py-version=3.11 - -# Discover python modules and packages in the file system subtree. -recursive=no - -# Add paths to the list of the source roots. Supports globbing patterns. The -# source root is an absolute path or a path relative to the current working -# directory used to determine a package namespace for modules located under the -# source root. -source-roots= - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages. -suggestion-mode=yes - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# In verbose mode, extra non-checker-related info will be displayed. -#verbose= - - -[BASIC] - -# Naming style matching correct argument names. -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style. If left empty, argument names will be checked with the set -# naming style. -#argument-rgx= - -# Naming style matching correct attribute names. -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style. If left empty, attribute names will be checked with the set naming -# style. -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma. -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Bad variable names regexes, separated by a comma. If names match any regex, -# they will always be refused -bad-names-rgxs= - -# Naming style matching correct class attribute names. -class-attribute-naming-style=any - -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style. If left empty, class attribute names will be checked -# with the set naming style. -#class-attribute-rgx= - -# Naming style matching correct class constant names. -class-const-naming-style=UPPER_CASE - -# Regular expression matching correct class constant names. Overrides class- -# const-naming-style. If left empty, class constant names will be checked with -# the set naming style. -#class-const-rgx= - -# Naming style matching correct class names. -class-naming-style=PascalCase - -# Regular expression matching correct class names. Overrides class-naming- -# style. If left empty, class names will be checked with the set naming style. -#class-rgx= - -# Naming style matching correct constant names. -const-naming-style=UPPER_CASE - -# Regular expression matching correct constant names. Overrides const-naming- -# style. If left empty, constant names will be checked with the set naming -# style. -#const-rgx= - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names. -function-naming-style=snake_case - -# Regular expression matching correct function names. Overrides function- -# naming-style. If left empty, function names will be checked with the set -# naming style. -#function-rgx= - -# Good variable names which should always be accepted, separated by a comma. -good-names=i, - j, - k, - ex, - Run, - _ - -# Good variable names regexes, separated by a comma. If names match any regex, -# they will always be accepted -good-names-rgxs= - -# Include a hint for the correct naming format with invalid-name. -include-naming-hint=no - -# Naming style matching correct inline iteration names. -inlinevar-naming-style=any - -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style. If left empty, inline iteration names will be checked -# with the set naming style. -#inlinevar-rgx= - -# Naming style matching correct method names. -method-naming-style=snake_case - -# Regular expression matching correct method names. Overrides method-naming- -# style. If left empty, method names will be checked with the set naming style. -#method-rgx= - -# Naming style matching correct module names. -module-naming-style=snake_case - -# Regular expression matching correct module names. Overrides module-naming- -# style. If left empty, module names will be checked with the set naming style. -#module-rgx= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -# These decorators are taken in consideration only for invalid-name. -property-classes=abc.abstractproperty - -# Regular expression matching correct type alias names. If left empty, type -# alias names will be checked with the set naming style. -#typealias-rgx= - -# Regular expression matching correct type variable names. If left empty, type -# variable names will be checked with the set naming style. -#typevar-rgx= - -# Naming style matching correct variable names. -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style. If left empty, variable names will be checked with the set -# naming style. -#variable-rgx= - - -[CLASSES] - -# Warn about protected attribute access inside special methods -check-protected-access-in-special-methods=no - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp, - asyncSetUp, - __post_init__ - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -# List of regular expressions of class ancestor names to ignore when counting -# public methods (see R0903) -exclude-too-few-public-methods= - -# List of qualified class names to ignore when counting class parents (see -# R0901) -ignored-parents= - -# Maximum number of arguments for function / method. -max-args=5 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in an if statement (see R0916). -max-bool-expr=5 - -# Maximum number of branch for function / method body. -max-branches=12 - -# Maximum number of locals for function / method body. -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body. -max-returns=6 - -# Maximum number of statements in function / method body. -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when caught. -overgeneral-exceptions=builtins.BaseException,builtins.Exception - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=100 - -# Maximum number of lines in a module. -max-module-lines=1000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[IMPORTS] - -# List of modules that can be imported at any level, not just the top level -# one. -allow-any-import-level= - -# Allow explicit reexports by alias from a package __init__. -allow-reexport-from-package=no - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Deprecated modules which should not be used, separated by a comma. -deprecated-modules= - -# Output a graph (.gv or any supported image format) of external dependencies -# to the given file (report RP0402 must not be disabled). -ext-import-graph= - -# Output a graph (.gv or any supported image format) of all (i.e. internal and -# external) dependencies to the given file (report RP0402 must not be -# disabled). -import-graph= - -# Output a graph (.gv or any supported image format) of internal dependencies -# to the given file (report RP0402 must not be disabled). -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Couples of modules and preferred modules, separated by a comma. -preferred-modules= - - -[LOGGING] - -# The type of string formatting that logging methods do. `old` means using % -# formatting, `new` is for `{}` formatting. -logging-format-style=old - -# Logging modules to check that the string format arguments are in logging -# function parameter format. -logging-modules=logging - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, -# UNDEFINED. -confidence=HIGH, - CONTROL_FLOW, - INFERENCE, - INFERENCE_FAILURE, - UNDEFINED - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once). You can also use "--disable=all" to -# disable everything first and then re-enable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use "--disable=all --enable=classes -# --disable=W". -disable=raw-checker-failed, - bad-inline-option, - locally-disabled, - file-ignored, - suppressed-message, - useless-suppression, - deprecated-pragma, - use-symbolic-message-instead - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable=c-extension-no-member - - -[METHOD_ARGS] - -# List of qualified names (i.e., library.method) which require a timeout -# parameter e.g. 'requests.api.get,requests.api.post' -timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX, - TODO - -# Regular expression of note tags to take in consideration. -notes-rgx= - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=sys.exit,argparse.parse_error - - -[REPORTS] - -# Python expression which should return a score less than or equal to 10. You -# have access to the variables 'fatal', 'error', 'warning', 'refactor', -# 'convention', and 'info' which contain the number of messages in each -# category, as well as 'statement' which is the total number of statements -# analyzed. This score is used by the global evaluation report (RP0004). -evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details. -msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio). You can also give a reporter class, e.g. -# mypackage.mymodule.MyReporterClass. -#output-format= - -# Tells whether to display a full report or only the messages. -reports=no - -# Activate the evaluation score. -score=yes - - -[SIMILARITIES] - -# Comments are removed from the similarity computation -ignore-comments=yes - -# Docstrings are removed from the similarity computation -ignore-docstrings=yes - -# Imports are removed from the similarity computation -ignore-imports=yes - -# Signatures are removed from the similarity computation -ignore-signatures=yes - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes. -max-spelling-suggestions=4 - -# Spelling dictionary name. No available dictionaries : You need to install -# both the python package and the system dependency for enchant to work.. -spelling-dict= - -# List of comma separated words that should be considered directives if they -# appear at the beginning of a comment and should not be checked. -spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains the private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to the private dictionary (see the -# --spelling-private-dict-file option) instead of raising a message. -spelling-store-unknown-words=no - - -[STRING] - -# This flag controls whether inconsistent-quotes generates a warning when the -# character used as a quote delimiter is used inconsistently within a module. -check-quote-consistency=no - -# This flag controls whether the implicit-str-concat should generate a warning -# on implicit string concatenation in sequences defined over several lines. -check-str-concat-over-line-jumps=no - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether to warn about missing members when the owner of the attribute -# is inferred to be None. -ignore-none=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of symbolic message names to ignore for Mixin members. -ignored-checks-for-mixins=no-member, - not-async-context-manager, - not-context-manager, - attribute-defined-outside-init - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - -# Regex pattern to define which classes are considered mixins. -mixin-class-rgx=.*[Mm]ixin - -# List of decorators that change the signature of a decorated function. -signature-mutators= - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid defining new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of names allowed to shadow builtins -allowed-redefined-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expected to -# not be used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io diff --git a/pyproject.toml b/pyproject.toml index 5d8de87..4edde73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "jellyfish-server-sdk" -version = "0.1.0" +version = "0.2.0-dev" description = "Python server SDK for the Jellyfish media server" authors = ["Jellyfish Team"] homepage = "https://github.com/jellyfish-dev/python-server-sdk" @@ -16,11 +16,12 @@ urllib3 = ">=1.25.3,<2" aenum = "^3.1.15" python-dateutil = "^2.8.2" betterproto = "2.0.0b6" +httpx = ">=0.20.0,<0.26.0" +attrs = ">=21.3.0" [tool.poetry.group.dev.dependencies] pylint = "^2.17.6" betterproto = { version = "= 2.0.0b6", extras = ["compiler"] } -black = "^23.10.0" pdoc = "^14.1.0" mkdocs = "^1.5.3" mike = "^2.0.0" @@ -40,12 +41,18 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] ci_test = "poetry_scripts:run_tests" format = "poetry_scripts:run_formatter" -check_format = "poetry_scripts:check_format" lint = "poetry_scripts:run_linter" +fix_lint = "poetry_scripts:run_linter_fix" generate_docs = "poetry_scripts:generate_docs" generate_client = "poetry_scripts:generate_client" [tool.ruff] select = ["F", "I"] -line-length = 120 -include = ["pyproject.toml", "jellyfish/_openapi_client/**/*.py"] +line-length = 100 + +[tool.ruff.lint] +select = ["F", "I", "E"] +ignore = [] + +[tool.ruff.extend-per-file-ignores] +"jellyfish/_openapi_client/**" = ["E501"] diff --git a/templates/model.py.jinja b/templates/model.py.jinja new file mode 100644 index 0000000..0c16e4e --- /dev/null +++ b/templates/model.py.jinja @@ -0,0 +1,203 @@ +from typing import Any, Dict, Type, TypeVar, Tuple, Optional, BinaryIO, TextIO, TYPE_CHECKING + +{% if model.additional_properties %} +from typing import List + +{% endif %} + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +{% if model.is_multipart_body %} +import json +{% endif %} + +from ..types import UNSET, Unset + +{% for relative in model.relative_imports %} +{{ relative }} +{% endfor %} + +{% for lazy_import in model.lazy_imports %} +{% if loop.first %} +if TYPE_CHECKING: +{% endif %} + {{ lazy_import }} +{% endfor %} + + +{% if model.additional_properties %} +{% set additional_property_type = 'Any' if model.additional_properties == True else model.additional_properties.get_type_string(quoted=not model.additional_properties.is_base_type) %} +{% endif %} + +{% set class_name = model.class_info.name %} +{% set module_name = model.class_info.module_name %} + +{% from "helpers.jinja" import safe_docstring %} + +T = TypeVar("T", bound="{{ class_name }}") + +{% macro class_docstring_content(model) %} + {% if model.title %}{{ model.title | wordwrap(116) }} + + {% endif -%} + {%- if model.description %}{{ model.description | wordwrap(116) }} + + {% endif %} + {% if not model.title and not model.description %} + {# Leave extra space so that a section doesn't start on the first line #} + + {% endif %} + {% if model.example %} + Example: + {{ model.example | string | wordwrap(112) | indent(12) }} + + {% endif %} +{% endmacro %} + +@_attrs_define +class {{ class_name }}: + {{ safe_docstring(class_docstring_content(model)) | indent(4) }} + + {% for property in model.required_properties + model.optional_properties %} + {% if property.default is none and property.required %} + {{ property.to_string() }} + """{{ property.description }}""" + {% endif %} + {% endfor %} + {% for property in model.required_properties + model.optional_properties %} + {% if property.default is not none or not property.required %} + {{ property.to_string() }} + """{{ property.description }}""" + {% endif %} + {% endfor %} + {% if model.additional_properties %} + additional_properties: Dict[str, {{ additional_property_type }}] = _attrs_field(init=False, factory=dict) + {% endif %} + +{% macro _to_dict(multipart=False) %} +{% for property in model.required_properties + model.optional_properties %} +{% import "property_templates/" + property.template as prop_template %} +{% if prop_template.transform %} +{{ prop_template.transform(property, "self." + property.python_name, property.python_name, multipart=multipart) }} +{% elif multipart %} +{{ property.python_name }} = self.{{ property.python_name }} if isinstance(self.{{ property.python_name }}, Unset) else (None, str(self.{{ property.python_name }}).encode(), "text/plain") +{% else %} +{{ property.python_name }} = self.{{ property.python_name }} +{% endif %} +{% endfor %} + +field_dict: Dict[str, Any] = {} +{% if model.additional_properties %} +{% if model.additional_properties.template %}{# Can be a bool instead of an object #} + {% import "property_templates/" + model.additional_properties.template as prop_template %} +{% else %} + {% set prop_template = None %} +{% endif %} +{% if prop_template and prop_template.transform %} +for prop_name, prop in self.additional_properties.items(): + {{ prop_template.transform(model.additional_properties, "prop", "field_dict[prop_name]", multipart=multipart, declare_type=false) | indent(4) }} +{% elif multipart %} +field_dict.update({ + key: (None, str(value).encode(), "text/plain") + for key, value in self.additional_properties.items() +}) +{% else %} +field_dict.update(self.additional_properties) +{% endif %} +{% endif %} +field_dict.update({ + {% for property in model.required_properties + model.optional_properties %} + {% if property.required %} + "{{ property.name }}": {{ property.python_name }}, + {% endif %} + {% endfor %} +}) +{% for property in model.optional_properties %} +{% if not property.required %} +if {{ property.python_name }} is not UNSET: + field_dict["{{ property.name }}"] = {{ property.python_name }} +{% endif %} +{% endfor %} + +return field_dict +{% endmacro %} + + def to_dict(self) -> Dict[str, Any]: + {% for lazy_import in model.lazy_imports %} + {{ lazy_import }} + {% endfor %} + {{ _to_dict() | indent(8) }} + +{% if model.is_multipart_body %} + def to_multipart(self) -> Dict[str, Any]: + {{ _to_dict(multipart=True) | indent(8) }} +{% endif %} + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + {% for lazy_import in model.lazy_imports %} + {{ lazy_import }} + {% endfor %} + d = src_dict.copy() +{% for property in model.required_properties + model.optional_properties %} + {% if property.required %} + {% set property_source = 'd.pop("' + property.name + '")' %} + {% else %} + {% set property_source = 'd.pop("' + property.name + '", UNSET)' %} + {% endif %} + {% import "property_templates/" + property.template as prop_template %} + {% if prop_template.construct %} + {{ prop_template.construct(property, property_source) | indent(8) }} + {% else %} + {{ property.python_name }} = {{ property_source }} + {% endif %} + +{% endfor %} + {{ module_name }} = cls( +{% for property in model.required_properties + model.optional_properties %} + {{ property.python_name }}={{ property.python_name }}, +{% endfor %} + ) + +{% if model.additional_properties %} + {% if model.additional_properties.template %}{# Can be a bool instead of an object #} + {% import "property_templates/" + model.additional_properties.template as prop_template %} + +{% if model.additional_properties.lazy_imports %} + {% for lazy_import in model.additional_properties.lazy_imports %} + {{ lazy_import }} + {% endfor %} +{% endif %} + {% else %} + {% set prop_template = None %} + {% endif %} + {% if prop_template and prop_template.construct %} + additional_properties = {} + for prop_name, prop_dict in d.items(): + {{ prop_template.construct(model.additional_properties, "prop_dict") | indent(12) }} + additional_properties[prop_name] = {{ model.additional_properties.python_name }} + + {{ module_name }}.additional_properties = additional_properties + {% else %} + {{ module_name }}.additional_properties = d + {% endif %} +{% endif %} + return {{ module_name }} + + {% if model.additional_properties %} + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> {{ additional_property_type }}: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: {{ additional_property_type }}) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties + {% endif %} diff --git a/templates/partial_header.mustache b/templates/partial_header.mustache deleted file mode 100644 index 5857428..0000000 --- a/templates/partial_header.mustache +++ /dev/null @@ -1,17 +0,0 @@ -""" -{{#appName}} -{{/appName}} -{{#appDescription}} - Python API wrapper for Jellyfish Media Server - -{{/appDescription}} - {{#version}} - The version of the OpenAPI document: {{{.}}} - {{/version}} - {{#infoEmail}} - Contact: {{{.}}} - {{/infoEmail}} - Generated by OpenAPI Generator (https://openapi-generator.tech) - - Do not edit the class manually. -""" # noqa: E501 diff --git a/tests/support/peer_socket.py b/tests/support/peer_socket.py index 14f2f86..768e015 100644 --- a/tests/support/peer_socket.py +++ b/tests/support/peer_socket.py @@ -1,15 +1,15 @@ # pylint: disable=locally-disabled, missing-class-docstring, missing-function-docstring, redefined-outer-name, too-few-public-methods, missing-module-docstring import asyncio -import betterproto +import betterproto from websockets import client from websockets.exceptions import ConnectionClosedOK from tests.support.protos.jellyfish import ( PeerMessage, - PeerMessageAuthRequest, PeerMessageAuthenticated, + PeerMessageAuthRequest, ) diff --git a/tests/support/protos/jellyfish/__init__.py b/tests/support/protos/jellyfish/__init__.py index c72002b..31b8bd2 100644 --- a/tests/support/protos/jellyfish/__init__.py +++ b/tests/support/protos/jellyfish/__init__.py @@ -10,12 +10,8 @@ @dataclass(eq=False, repr=False) class PeerMessage(betterproto.Message): - authenticated: "PeerMessageAuthenticated" = betterproto.message_field( - 1, group="content" - ) - auth_request: "PeerMessageAuthRequest" = betterproto.message_field( - 2, group="content" - ) + authenticated: "PeerMessageAuthenticated" = betterproto.message_field(1, group="content") + auth_request: "PeerMessageAuthRequest" = betterproto.message_field(2, group="content") media_event: "PeerMessageMediaEvent" = betterproto.message_field(3, group="content") diff --git a/tests/support/webhook_notifier.py b/tests/support/webhook_notifier.py index 8c1c078..730f91d 100644 --- a/tests/support/webhook_notifier.py +++ b/tests/support/webhook_notifier.py @@ -1,6 +1,7 @@ # pylint: disable=locally-disabled, missing-class-docstring, missing-function-docstring, redefined-outer-name, too-few-public-methods, missing-module-docstring, global-statement -from flask import Flask, request, Response +from flask import Flask, Response, request + from jellyfish import receive_json app = Flask(__name__) diff --git a/tests/test_notifier.py b/tests/test_notifier.py index b04c881..cddb0c4 100644 --- a/tests/test_notifier.py +++ b/tests/test_notifier.py @@ -1,28 +1,26 @@ # pylint: disable=locally-disabled, missing-class-docstring, missing-function-docstring, redefined-outer-name, too-few-public-methods, missing-module-docstring -import os import asyncio +import os import socket import time from multiprocessing import Process, Queue -import requests import pytest +import requests -from jellyfish import Notifier, RoomApi, PeerOptionsWebRTC +from jellyfish import Notifier, PeerOptionsWebRTC, RoomApi from jellyfish.events import ( - ServerMessageRoomCreated, - ServerMessageRoomDeleted, + ServerMessageMetricsReport, ServerMessagePeerConnected, ServerMessagePeerDisconnected, - ServerMessageMetricsReport, + ServerMessageRoomCreated, + ServerMessageRoomDeleted, ) - -from tests.support.peer_socket import PeerSocket from tests.support.asyncio_utils import assert_events, assert_metrics, cancel +from tests.support.peer_socket import PeerSocket from tests.support.webhook_notifier import run_server - HOST = "jellyfish" if os.getenv("DOCKER_TEST") == "TRUE" else "localhost" SERVER_ADDRESS = f"{HOST}:5002" SERVER_API_TOKEN = "development" @@ -56,9 +54,7 @@ def start_server(): class TestConnectingToServer: @pytest.mark.asyncio async def test_valid_credentials(self): - notifier = Notifier( - server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN - ) + notifier = Notifier(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) notifier_task = asyncio.create_task(notifier.connect()) await notifier.wait_ready() @@ -69,9 +65,7 @@ async def test_valid_credentials(self): @pytest.mark.asyncio async def test_invalid_credentials(self): - notifier = Notifier( - server_address=SERVER_ADDRESS, server_api_token="wrong_token" - ) + notifier = Notifier(server_address=SERVER_ADDRESS, server_api_token="wrong_token") task = asyncio.create_task(notifier.connect()) @@ -86,9 +80,7 @@ def room_api(): @pytest.fixture def notifier(): - notifier = Notifier( - server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN - ) + notifier = Notifier(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) @notifier.on_server_notification def handle_notification(_server_notification): @@ -121,9 +113,7 @@ async def test_room_created_deleted(self, room_api: RoomApi, notifier: Notifier) self.assert_event(event) @pytest.mark.asyncio - async def test_peer_connected_disconnected( - self, room_api: RoomApi, notifier: Notifier - ): + async def test_peer_connected_disconnected(self, room_api: RoomApi, notifier: Notifier): event_checks = [ ServerMessageRoomCreated, ServerMessagePeerConnected, @@ -156,9 +146,7 @@ async def test_peer_connected_disconnected( self.assert_event(event) @pytest.mark.asyncio - async def test_peer_connected_room_deleted( - self, room_api: RoomApi, notifier: Notifier - ): + async def test_peer_connected_room_deleted(self, room_api: RoomApi, notifier: Notifier): event_checks = [ ServerMessageRoomCreated, ServerMessagePeerConnected, @@ -202,9 +190,7 @@ async def test_metrics_with_one_peer(self, room_api: RoomApi, notifier: Notifier await peer_socket.wait_ready() - assert_task = asyncio.create_task( - assert_metrics(notifier, [ServerMessageMetricsReport]) - ) + assert_task = asyncio.create_task(assert_metrics(notifier, [ServerMessageMetricsReport])) notifier_task = asyncio.create_task(notifier.connect()) await assert_task diff --git a/tests/test_recording_api.py b/tests/test_recording_api.py index 8d03f8d..a906a3e 100644 --- a/tests/test_recording_api.py +++ b/tests/test_recording_api.py @@ -16,9 +16,7 @@ @pytest.fixture def recording_api(): - return RecordingApi( - server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN - ) + return RecordingApi(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) class TestGetList: diff --git a/tests/test_room_api.py b/tests/test_room_api.py index cfc5140..794ad89 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -5,29 +5,30 @@ import pytest -from jellyfish import RoomApi, RoomConfig -from jellyfish import Room, ComponentHLS, ComponentRTSP from jellyfish import ( - ComponentOptionsRTSP, + ComponentHLS, ComponentOptionsHLS, ComponentOptionsHLSSubscribeMode, + ComponentOptionsRTSP, + ComponentPropertiesHLS, + ComponentPropertiesHLSSubscribeMode, + ComponentPropertiesRTSP, + ComponentRTSP, + Peer, PeerOptionsWebRTC, + PeerStatus, + Room, + RoomApi, + RoomConfig, + RoomConfigVideoCodec, ) - -# from jellyfish import UnauthorizedException, NotFoundException, BadRequestException - - HOST = "jellyfish" if os.getenv("DOCKER_TEST") == "TRUE" else "localhost" SERVER_ADDRESS = f"{HOST}:5002" SERVER_API_TOKEN = "development" MAX_PEERS = 10 CODEC_H264 = "h264" -PEER_WEBRTC = "webrtc" - -COMPONENT_HLS = "hls" -COMPONENT_RTSP = "rtsp" HLS_OPTIONS = ComponentOptionsHLS() RTSP_OPTIONS = ComponentOptionsRTSP( @@ -43,9 +44,7 @@ def test_invalid_token(self): room_api.create_room() def test_valid_token(self): - room_api = RoomApi( - server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN - ) + room_api = RoomApi(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) _, room = room_api.create_room() @@ -74,7 +73,7 @@ def test_no_params(self, room_api): assert room == Room( components=[], - config=RoomConfig(max_peers=None, video_codec=None), + config=RoomConfig(max_peers=None, video_codec=None, webhook_url=None), id=room.id, peers=[], ) @@ -82,11 +81,15 @@ def test_no_params(self, room_api): assert room in room_api.get_all_rooms() def test_valid_params(self, room_api): - _, room = room_api.create_room(max_peers=MAX_PEERS, video_codec=CODEC_H264) + _, room = room_api.create_room( + max_peers=MAX_PEERS, video_codec=RoomConfigVideoCodec(CODEC_H264) + ) assert room == Room( components=[], - config=RoomConfig(max_peers=MAX_PEERS, video_codec=CODEC_H264), + config=RoomConfig( + max_peers=MAX_PEERS, video_codec=RoomConfigVideoCodec(CODEC_H264), webhook_url=None + ), id=room.id, peers=[], ) @@ -94,7 +97,7 @@ def test_valid_params(self, room_api): def test_invalid_max_peers(self, room_api): with pytest.raises(RuntimeError): - room_api.create_room(max_peers="10", video_codec=CODEC_H264) + room_api.create_room(max_peers="10", video_codec=CODEC_H264, webhook_url=None) def test_invalid_video_codec(self, room_api): with pytest.raises(ValueError): @@ -130,7 +133,7 @@ def test_valid(self, room_api: RoomApi): components=[], peers=[], id=room.id, - config=RoomConfig(max_peers=None, video_codec=None), + config=RoomConfig(max_peers=None, video_codec=None, webhook_url=None), ) == room_api.get_room(room.id) def test_invalid(self, room_api: RoomApi): @@ -146,14 +149,30 @@ def test_with_options_hls(self, room_api: RoomApi): component = room_api.get_room(room.id).components[0] - assert isinstance(component, ComponentHLS) + properties = ComponentPropertiesHLS( + low_latency=False, + persistent=False, + playable=False, + subscribe_mode=ComponentPropertiesHLSSubscribeMode("auto"), + target_window_duration=None, + ) + properties.additional_properties = {"s3": None} + + component_hls = ComponentHLS(id=component.id, type="hls", properties=properties) + + assert component == component_hls def test_with_options_rtsp(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) room_api.add_component(room.id, options=RTSP_OPTIONS) component = room_api.get_room(room.id).components[0] - assert isinstance(component, ComponentRTSP) + + component_rtsp = ComponentRTSP( + id=component.id, type="rtsp", properties=ComponentPropertiesRTSP() + ) + + assert component == component_rtsp def test_invalid_type(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) @@ -182,9 +201,7 @@ def test_valid_subscription(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) _ = room_api.add_component( room.id, - options=ComponentOptionsHLS( - subscribe_mode=ComponentOptionsHLSSubscribeMode("manual") - ), + options=ComponentOptionsHLS(subscribe_mode=ComponentOptionsHLSSubscribeMode("manual")), ) assert room_api.hls_subscribe(room.id, ["track-id"]) is None @@ -196,9 +213,8 @@ def test_invalid_subscription(self, room_api: RoomApi): class TestAddPeer: - def _assert_peer_created(self, room_api, peer, room_id): - assert peer.status == "disconnected" - assert peer.type == PEER_WEBRTC + def _assert_peer_created(self, room_api, webrtc_peer, room_id): + peer = Peer(id=webrtc_peer.id, type="webrtc", status=PeerStatus("disconnected")) room = room_api.get_room(room_id) assert peer in room.peers @@ -206,9 +222,7 @@ def _assert_peer_created(self, room_api, peer, room_id): def test_with_specified_options(self, room_api: RoomApi): _, room = room_api.create_room() - _token, peer = room_api.add_peer( - room.id, options=PeerOptionsWebRTC(enable_simulcast=True) - ) + _token, peer = room_api.add_peer(room.id, options=PeerOptionsWebRTC(enable_simulcast=True)) self._assert_peer_created(room_api, peer, room.id) @@ -223,9 +237,7 @@ def test_default_options(self, room_api: RoomApi): class TestDeletePeer: def test_valid(self, room_api: RoomApi): _, room = room_api.create_room() - _, peer = room_api.add_peer( - room.id, options=PeerOptionsWebRTC(enable_simulcast=True) - ) + _, peer = room_api.add_peer(room.id, options=PeerOptionsWebRTC(enable_simulcast=True)) room_api.delete_peer(room.id, peer.id) From a2defadeae2b392aadc61adad9b4173ecbdeab8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Thu, 14 Dec 2023 20:50:11 +0100 Subject: [PATCH 4/9] Add enum template --- .circleci/config.yml | 3 --- jellyfish/__init__.py | 14 +++++++------- .../models/component_details_response.py | 10 +++++++++- .../models/component_options_hls_subscribe_mode.py | 4 ++++ .../component_properties_hls_subscribe_mode.py | 4 ++++ jellyfish/_openapi_client/models/peer_status.py | 4 ++++ .../models/room_config_video_codec.py | 4 ++++ {templates => openapi_templates}/model.py.jinja | 0 openapi_templates/str_enum.py.jinja | 11 +++++++++++ poetry_scripts.py | 3 ++- 10 files changed, 45 insertions(+), 12 deletions(-) rename {templates => openapi_templates}/model.py.jinja (100%) create mode 100644 openapi_templates/str_enum.py.jinja diff --git a/.circleci/config.yml b/.circleci/config.yml index 3512303..ef7f185 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,9 +20,6 @@ jobs: - run: name: Lint command: poetry run lint - - run: - name: Check code formatting - command: poetry run check_format - persist_to_workspace: root: ~/project paths: diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index 4c3c2ba..6a4facd 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -32,24 +32,24 @@ from jellyfish._ws_notifier import Notifier __all__ = [ - "ComponentPropertiesHLSSubscribeMode", - "RoomConfigVideoCodec", - "ComponentPropertiesRTSP", "RoomApi", "RecordingApi", "Notifier", "receive_json", "Room", + "RoomConfig", + "RoomConfigVideoCodec", "Peer", + "PeerOptionsWebRTC", "PeerStatus", "ComponentHLS", - "ComponentPropertiesHLS", + "ComponentOptionsHLS", "ComponentOptionsHLSSubscribeMode", + "ComponentPropertiesHLS", + "ComponentPropertiesHLSSubscribeMode", "ComponentRTSP", - "ComponentOptionsHLS", - "RoomConfig", "ComponentOptionsRTSP", - "PeerOptionsWebRTC", + "ComponentPropertiesRTSP", "events", ] diff --git a/jellyfish/_openapi_client/models/component_details_response.py b/jellyfish/_openapi_client/models/component_details_response.py index 1d3332d..1a1e0a9 100644 --- a/jellyfish/_openapi_client/models/component_details_response.py +++ b/jellyfish/_openapi_client/models/component_details_response.py @@ -1,4 +1,12 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union +from typing import ( + TYPE_CHECKING, + Any, + Dict, + List, + Type, + TypeVar, + Union, +) from attrs import define as _attrs_define from attrs import field as _attrs_field diff --git a/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py b/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py index 99b23e7..8f5b9cd 100644 --- a/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py +++ b/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py @@ -2,8 +2,12 @@ class ComponentOptionsHLSSubscribeMode(str, Enum): + """Whether the HLS component should subscribe to tracks automatically or manually.""" + AUTO = "auto" + """ComponentOptionsHLSSubscribeMode: auto""" MANUAL = "manual" + """ComponentOptionsHLSSubscribeMode: manual""" def __str__(self) -> str: return str(self.value) diff --git a/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py b/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py index 09c6719..3b71f3c 100644 --- a/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py +++ b/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py @@ -2,8 +2,12 @@ class ComponentPropertiesHLSSubscribeMode(str, Enum): + """Whether the HLS component should subscribe to tracks automatically or manually""" + AUTO = "auto" + """ComponentPropertiesHLSSubscribeMode: auto""" MANUAL = "manual" + """ComponentPropertiesHLSSubscribeMode: manual""" def __str__(self) -> str: return str(self.value) diff --git a/jellyfish/_openapi_client/models/peer_status.py b/jellyfish/_openapi_client/models/peer_status.py index c11f20c..5f1a5f2 100644 --- a/jellyfish/_openapi_client/models/peer_status.py +++ b/jellyfish/_openapi_client/models/peer_status.py @@ -2,8 +2,12 @@ class PeerStatus(str, Enum): + """Informs about the peer status""" + CONNECTED = "connected" + """PeerStatus: connected""" DISCONNECTED = "disconnected" + """PeerStatus: disconnected""" def __str__(self) -> str: return str(self.value) diff --git a/jellyfish/_openapi_client/models/room_config_video_codec.py b/jellyfish/_openapi_client/models/room_config_video_codec.py index 470fa4d..8320b78 100644 --- a/jellyfish/_openapi_client/models/room_config_video_codec.py +++ b/jellyfish/_openapi_client/models/room_config_video_codec.py @@ -2,8 +2,12 @@ class RoomConfigVideoCodec(str, Enum): + """Enforces video codec for each peer in the room""" + H264 = "h264" + """RoomConfigVideoCodec: h264""" VP8 = "vp8" + """RoomConfigVideoCodec: vp8""" def __str__(self) -> str: return str(self.value) diff --git a/templates/model.py.jinja b/openapi_templates/model.py.jinja similarity index 100% rename from templates/model.py.jinja rename to openapi_templates/model.py.jinja diff --git a/openapi_templates/str_enum.py.jinja b/openapi_templates/str_enum.py.jinja new file mode 100644 index 0000000..e28fdfb --- /dev/null +++ b/openapi_templates/str_enum.py.jinja @@ -0,0 +1,11 @@ +from enum import Enum + +class {{ enum.class_info.name }}(str, Enum): + """{{ enum.description }}""" + {% for key, value in enum.values|dictsort(true) %} + {{ key }} = "{{ value }}" + """{{ enum.class_info.name }}: {{ value }}""" + {% endfor %} + + def __str__(self) -> str: + return str(self.value) \ No newline at end of file diff --git a/poetry_scripts.py b/poetry_scripts.py index 7e190c3..1a049d1 100644 --- a/poetry_scripts.py +++ b/poetry_scripts.py @@ -59,5 +59,6 @@ def generate_client(): check_exit_code( "openapi-python-client generate\ --url https://raw.githubusercontent.com/jellyfish-dev/jellyfish/main/openapi.yaml \ - --config openapi-python-client-config.yaml" + --config openapi-python-client-config.yaml \ + --custom-template-path=openapi_templates" ) From d135601e5dac137a0ae5fb0f6db09eec49efad11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Thu, 14 Dec 2023 22:36:48 +0100 Subject: [PATCH 5/9] Fix ServerMessage docs --- .../models/add_component_json_body.py | 4 ++++ .../_openapi_client/models/add_peer_json_body.py | 4 ++++ .../models/component_details_response.py | 14 +++++--------- jellyfish/_openapi_client/models/component_file.py | 4 ++++ jellyfish/_openapi_client/models/component_hls.py | 4 ++++ .../models/component_options_file.py | 4 ++++ .../models/component_options_hls.py | 4 ++++ .../models/component_options_hls_subscribe_mode.py | 2 -- .../models/component_options_rtsp.py | 4 ++++ .../models/component_properties_hls.py | 4 ++++ .../component_properties_hls_subscribe_mode.py | 2 -- .../models/component_properties_rtsp.py | 5 +++++ jellyfish/_openapi_client/models/component_rtsp.py | 4 ++++ jellyfish/_openapi_client/models/error.py | 4 ++++ jellyfish/_openapi_client/models/peer.py | 4 ++++ .../models/peer_details_response.py | 4 ++++ .../models/peer_details_response_data.py | 4 ++++ .../_openapi_client/models/peer_options_web_rtc.py | 4 ++++ jellyfish/_openapi_client/models/peer_status.py | 2 -- .../models/recording_list_response.py | 4 ++++ jellyfish/_openapi_client/models/room.py | 4 ++++ jellyfish/_openapi_client/models/room_config.py | 4 ++++ .../models/room_config_video_codec.py | 2 -- .../models/room_create_details_response.py | 4 ++++ .../models/room_create_details_response_data.py | 4 ++++ .../models/room_details_response.py | 4 ++++ .../models/rooms_listing_response.py | 4 ++++ jellyfish/_openapi_client/models/s3_credentials.py | 4 ++++ .../_openapi_client/models/subscription_config.py | 4 ++++ jellyfish/_webhook_notifier.py | 12 +++++++++--- jellyfish/_ws_notifier.py | 4 ++-- jellyfish/events/__init__.py | 6 ------ jellyfish/events/_protos/jellyfish/__init__.py | 14 ++++++++++++++ openapi-python-client-config.yaml | 2 +- openapi_templates/model.py.jinja | 4 ++++ openapi_templates/str_enum.py.jinja | 1 - poetry_scripts.py | 2 +- protos | 2 +- tests/test_recording_api.py | 2 +- 39 files changed, 135 insertions(+), 33 deletions(-) diff --git a/jellyfish/_openapi_client/models/add_component_json_body.py b/jellyfish/_openapi_client/models/add_component_json_body.py index eeac61d..153b23e 100644 --- a/jellyfish/_openapi_client/models/add_component_json_body.py +++ b/jellyfish/_openapi_client/models/add_component_json_body.py @@ -25,8 +25,10 @@ class AddComponentJsonBody: ] = UNSET """Component-specific options""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" from ..models.component_options_hls import ComponentOptionsHLS from ..models.component_options_rtsp import ComponentOptionsRTSP @@ -58,6 +60,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.component_options_file import ComponentOptionsFile from ..models.component_options_hls import ComponentOptionsHLS from ..models.component_options_rtsp import ComponentOptionsRTSP @@ -104,6 +107,7 @@ def _parse_options( @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/add_peer_json_body.py b/jellyfish/_openapi_client/models/add_peer_json_body.py index ef3893a..bf67477 100644 --- a/jellyfish/_openapi_client/models/add_peer_json_body.py +++ b/jellyfish/_openapi_client/models/add_peer_json_body.py @@ -19,8 +19,10 @@ class AddPeerJsonBody: type: str """Peer type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" options = self.options.to_dict() type = self.type @@ -38,6 +40,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.peer_options_web_rtc import PeerOptionsWebRTC d = src_dict.copy() @@ -55,6 +58,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_details_response.py b/jellyfish/_openapi_client/models/component_details_response.py index 1a1e0a9..313d958 100644 --- a/jellyfish/_openapi_client/models/component_details_response.py +++ b/jellyfish/_openapi_client/models/component_details_response.py @@ -1,12 +1,4 @@ -from typing import ( - TYPE_CHECKING, - Any, - Dict, - List, - Type, - TypeVar, - Union, -) +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -27,8 +19,10 @@ class ComponentDetailsResponse: data: Union["ComponentFile", "ComponentHLS", "ComponentRTSP"] """Describes component""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP @@ -55,6 +49,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP @@ -95,6 +90,7 @@ def _parse_data(data: object) -> Union["ComponentFile", "ComponentHLS", "Compone @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_file.py b/jellyfish/_openapi_client/models/component_file.py index be0427b..ee01e93 100644 --- a/jellyfish/_openapi_client/models/component_file.py +++ b/jellyfish/_openapi_client/models/component_file.py @@ -15,8 +15,10 @@ class ComponentFile: type: str """Component type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" id = self.id type = self.type @@ -33,6 +35,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() id = d.pop("id") @@ -48,6 +51,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_hls.py b/jellyfish/_openapi_client/models/component_hls.py index c7b6647..a78a4ff 100644 --- a/jellyfish/_openapi_client/models/component_hls.py +++ b/jellyfish/_openapi_client/models/component_hls.py @@ -21,8 +21,10 @@ class ComponentHLS: type: str """Component type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" id = self.id properties = self.properties.to_dict() @@ -42,6 +44,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.component_properties_hls import ComponentPropertiesHLS d = src_dict.copy() @@ -62,6 +65,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_options_file.py b/jellyfish/_openapi_client/models/component_options_file.py index c5f1111..7760da7 100644 --- a/jellyfish/_openapi_client/models/component_options_file.py +++ b/jellyfish/_openapi_client/models/component_options_file.py @@ -13,8 +13,10 @@ class ComponentOptionsFile: file_path: str """Path to track file. Must be either OPUS encapsulated in Ogg or raw h264""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" file_path = self.file_path field_dict: Dict[str, Any] = {} @@ -29,6 +31,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() file_path = d.pop("filePath") @@ -41,6 +44,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_options_hls.py b/jellyfish/_openapi_client/models/component_options_hls.py index f0d45eb..6b4bd00 100644 --- a/jellyfish/_openapi_client/models/component_options_hls.py +++ b/jellyfish/_openapi_client/models/component_options_hls.py @@ -30,8 +30,10 @@ class ComponentOptionsHLS: target_window_duration: Union[Unset, None, int] = UNSET """Duration of stream available for viewer""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" low_latency = self.low_latency persistent = self.persistent s3: Union[Unset, None, Dict[str, Any]] = UNSET @@ -62,6 +64,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.s3_credentials import S3Credentials d = src_dict.copy() @@ -100,6 +103,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py b/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py index 8f5b9cd..5336deb 100644 --- a/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py +++ b/jellyfish/_openapi_client/models/component_options_hls_subscribe_mode.py @@ -5,9 +5,7 @@ class ComponentOptionsHLSSubscribeMode(str, Enum): """Whether the HLS component should subscribe to tracks automatically or manually.""" AUTO = "auto" - """ComponentOptionsHLSSubscribeMode: auto""" MANUAL = "manual" - """ComponentOptionsHLSSubscribeMode: manual""" def __str__(self) -> str: return str(self.value) diff --git a/jellyfish/_openapi_client/models/component_options_rtsp.py b/jellyfish/_openapi_client/models/component_options_rtsp.py index e261edb..83dc334 100644 --- a/jellyfish/_openapi_client/models/component_options_rtsp.py +++ b/jellyfish/_openapi_client/models/component_options_rtsp.py @@ -23,8 +23,10 @@ class ComponentOptionsRTSP: rtp_port: Union[Unset, int] = 20000 """Local port RTP stream will be received at""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" source_uri = self.source_uri keep_alive_interval = self.keep_alive_interval pierce_nat = self.pierce_nat @@ -51,6 +53,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() source_uri = d.pop("sourceUri") @@ -75,6 +78,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_properties_hls.py b/jellyfish/_openapi_client/models/component_properties_hls.py index 00553d6..34241e5 100644 --- a/jellyfish/_openapi_client/models/component_properties_hls.py +++ b/jellyfish/_openapi_client/models/component_properties_hls.py @@ -23,8 +23,10 @@ class ComponentPropertiesHLS: target_window_duration: Optional[int] """Duration of stream available for viewer""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" low_latency = self.low_latency persistent = self.persistent playable = self.playable @@ -48,6 +50,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() low_latency = d.pop("lowLatency") @@ -72,6 +75,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py b/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py index 3b71f3c..d95a59e 100644 --- a/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py +++ b/jellyfish/_openapi_client/models/component_properties_hls_subscribe_mode.py @@ -5,9 +5,7 @@ class ComponentPropertiesHLSSubscribeMode(str, Enum): """Whether the HLS component should subscribe to tracks automatically or manually""" AUTO = "auto" - """ComponentPropertiesHLSSubscribeMode: auto""" MANUAL = "manual" - """ComponentPropertiesHLSSubscribeMode: manual""" def __str__(self) -> str: return str(self.value) diff --git a/jellyfish/_openapi_client/models/component_properties_rtsp.py b/jellyfish/_openapi_client/models/component_properties_rtsp.py index 635e178..e8a86b0 100644 --- a/jellyfish/_openapi_client/models/component_properties_rtsp.py +++ b/jellyfish/_openapi_client/models/component_properties_rtsp.py @@ -11,8 +11,11 @@ class ComponentPropertiesRTSP: """Properties specific to the RTSP component""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" + field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) @@ -21,6 +24,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() component_properties_rtsp = cls() @@ -29,6 +33,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/component_rtsp.py b/jellyfish/_openapi_client/models/component_rtsp.py index 70c68a9..c2b1f0e 100644 --- a/jellyfish/_openapi_client/models/component_rtsp.py +++ b/jellyfish/_openapi_client/models/component_rtsp.py @@ -21,8 +21,10 @@ class ComponentRTSP: type: str """Component type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" id = self.id properties = self.properties.to_dict() @@ -42,6 +44,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.component_properties_rtsp import ComponentPropertiesRTSP d = src_dict.copy() @@ -62,6 +65,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/error.py b/jellyfish/_openapi_client/models/error.py index 3fa9ea2..d6f271d 100644 --- a/jellyfish/_openapi_client/models/error.py +++ b/jellyfish/_openapi_client/models/error.py @@ -13,8 +13,10 @@ class Error: errors: str """Error details""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" errors = self.errors field_dict: Dict[str, Any] = {} @@ -29,6 +31,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() errors = d.pop("errors") @@ -41,6 +44,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/peer.py b/jellyfish/_openapi_client/models/peer.py index b4459ef..2c435fd 100644 --- a/jellyfish/_openapi_client/models/peer.py +++ b/jellyfish/_openapi_client/models/peer.py @@ -19,8 +19,10 @@ class Peer: type: str """Peer type""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" id = self.id status = self.status.value @@ -40,6 +42,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() id = d.pop("id") @@ -58,6 +61,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/peer_details_response.py b/jellyfish/_openapi_client/models/peer_details_response.py index 5a024ad..5a90e27 100644 --- a/jellyfish/_openapi_client/models/peer_details_response.py +++ b/jellyfish/_openapi_client/models/peer_details_response.py @@ -17,8 +17,10 @@ class PeerDetailsResponse: data: "PeerDetailsResponseData" """""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" data = self.data.to_dict() field_dict: Dict[str, Any] = {} @@ -33,6 +35,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.peer_details_response_data import PeerDetailsResponseData d = src_dict.copy() @@ -47,6 +50,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/peer_details_response_data.py b/jellyfish/_openapi_client/models/peer_details_response_data.py index 92140f9..fb298ca 100644 --- a/jellyfish/_openapi_client/models/peer_details_response_data.py +++ b/jellyfish/_openapi_client/models/peer_details_response_data.py @@ -19,8 +19,10 @@ class PeerDetailsResponseData: token: str """Token for authorizing websocket connection""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" peer = self.peer.to_dict() token = self.token @@ -38,6 +40,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.peer import Peer d = src_dict.copy() @@ -55,6 +58,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/peer_options_web_rtc.py b/jellyfish/_openapi_client/models/peer_options_web_rtc.py index e1355be..0163ef7 100644 --- a/jellyfish/_openapi_client/models/peer_options_web_rtc.py +++ b/jellyfish/_openapi_client/models/peer_options_web_rtc.py @@ -15,8 +15,10 @@ class PeerOptionsWebRTC: enable_simulcast: Union[Unset, bool] = True """Enables the peer to use simulcast""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" enable_simulcast = self.enable_simulcast field_dict: Dict[str, Any] = {} @@ -29,6 +31,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() enable_simulcast = d.pop("enableSimulcast", UNSET) @@ -41,6 +44,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/peer_status.py b/jellyfish/_openapi_client/models/peer_status.py index 5f1a5f2..f922886 100644 --- a/jellyfish/_openapi_client/models/peer_status.py +++ b/jellyfish/_openapi_client/models/peer_status.py @@ -5,9 +5,7 @@ class PeerStatus(str, Enum): """Informs about the peer status""" CONNECTED = "connected" - """PeerStatus: connected""" DISCONNECTED = "disconnected" - """PeerStatus: disconnected""" def __str__(self) -> str: return str(self.value) diff --git a/jellyfish/_openapi_client/models/recording_list_response.py b/jellyfish/_openapi_client/models/recording_list_response.py index 716ed4b..de63699 100644 --- a/jellyfish/_openapi_client/models/recording_list_response.py +++ b/jellyfish/_openapi_client/models/recording_list_response.py @@ -13,8 +13,10 @@ class RecordingListResponse: data: List[str] """None""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" data = self.data field_dict: Dict[str, Any] = {} @@ -29,6 +31,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() data = cast(List[str], d.pop("data")) @@ -41,6 +44,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/room.py b/jellyfish/_openapi_client/models/room.py index 711f067..62fcbae 100644 --- a/jellyfish/_openapi_client/models/room.py +++ b/jellyfish/_openapi_client/models/room.py @@ -27,8 +27,10 @@ class Room: peers: List["Peer"] """List of all peers""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP @@ -71,6 +73,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.component_file import ComponentFile from ..models.component_hls import ComponentHLS from ..models.component_rtsp import ComponentRTSP @@ -134,6 +137,7 @@ def _parse_components_item( @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/room_config.py b/jellyfish/_openapi_client/models/room_config.py index 5a1aa9c..ede86ec 100644 --- a/jellyfish/_openapi_client/models/room_config.py +++ b/jellyfish/_openapi_client/models/room_config.py @@ -20,8 +20,10 @@ class RoomConfig: webhook_url: Union[Unset, None, str] = UNSET """URL where Jellyfish notifications will be sent""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" max_peers = self.max_peers video_codec: Union[Unset, None, str] = UNSET if not isinstance(self.video_codec, Unset): @@ -43,6 +45,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() max_peers = d.pop("maxPeers", UNSET) @@ -68,6 +71,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/room_config_video_codec.py b/jellyfish/_openapi_client/models/room_config_video_codec.py index 8320b78..972e4dd 100644 --- a/jellyfish/_openapi_client/models/room_config_video_codec.py +++ b/jellyfish/_openapi_client/models/room_config_video_codec.py @@ -5,9 +5,7 @@ class RoomConfigVideoCodec(str, Enum): """Enforces video codec for each peer in the room""" H264 = "h264" - """RoomConfigVideoCodec: h264""" VP8 = "vp8" - """RoomConfigVideoCodec: vp8""" def __str__(self) -> str: return str(self.value) diff --git a/jellyfish/_openapi_client/models/room_create_details_response.py b/jellyfish/_openapi_client/models/room_create_details_response.py index 207bf33..fe88790 100644 --- a/jellyfish/_openapi_client/models/room_create_details_response.py +++ b/jellyfish/_openapi_client/models/room_create_details_response.py @@ -17,8 +17,10 @@ class RoomCreateDetailsResponse: data: "RoomCreateDetailsResponseData" """""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" data = self.data.to_dict() field_dict: Dict[str, Any] = {} @@ -33,6 +35,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.room_create_details_response_data import RoomCreateDetailsResponseData d = src_dict.copy() @@ -47,6 +50,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/room_create_details_response_data.py b/jellyfish/_openapi_client/models/room_create_details_response_data.py index f5df3d6..09bab6e 100644 --- a/jellyfish/_openapi_client/models/room_create_details_response_data.py +++ b/jellyfish/_openapi_client/models/room_create_details_response_data.py @@ -19,8 +19,10 @@ class RoomCreateDetailsResponseData: room: "Room" """Description of the room state""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" jellyfish_address = self.jellyfish_address room = self.room.to_dict() @@ -37,6 +39,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.room import Room d = src_dict.copy() @@ -54,6 +57,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/room_details_response.py b/jellyfish/_openapi_client/models/room_details_response.py index efc11bd..9d3427b 100644 --- a/jellyfish/_openapi_client/models/room_details_response.py +++ b/jellyfish/_openapi_client/models/room_details_response.py @@ -17,8 +17,10 @@ class RoomDetailsResponse: data: "Room" """Description of the room state""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" data = self.data.to_dict() field_dict: Dict[str, Any] = {} @@ -33,6 +35,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.room import Room d = src_dict.copy() @@ -47,6 +50,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/rooms_listing_response.py b/jellyfish/_openapi_client/models/rooms_listing_response.py index 02d3ef6..828f4f7 100644 --- a/jellyfish/_openapi_client/models/rooms_listing_response.py +++ b/jellyfish/_openapi_client/models/rooms_listing_response.py @@ -17,8 +17,10 @@ class RoomsListingResponse: data: List["Room"] """None""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" data = [] for data_item_data in self.data: data_item = data_item_data.to_dict() @@ -37,6 +39,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" from ..models.room import Room d = src_dict.copy() @@ -56,6 +59,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/s3_credentials.py b/jellyfish/_openapi_client/models/s3_credentials.py index 41292bf..f662177 100644 --- a/jellyfish/_openapi_client/models/s3_credentials.py +++ b/jellyfish/_openapi_client/models/s3_credentials.py @@ -22,8 +22,10 @@ class S3Credentials: secret_access_key: str """The secret key that is linked to the Access Key ID.""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" access_key_id = self.access_key_id bucket = self.bucket region = self.region @@ -44,6 +46,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() access_key_id = d.pop("accessKeyId") @@ -65,6 +68,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_openapi_client/models/subscription_config.py b/jellyfish/_openapi_client/models/subscription_config.py index 8ad49ff..4a33621 100644 --- a/jellyfish/_openapi_client/models/subscription_config.py +++ b/jellyfish/_openapi_client/models/subscription_config.py @@ -15,8 +15,10 @@ class SubscriptionConfig: tracks: Union[Unset, List[str]] = UNSET """List of tracks that hls endpoint will subscribe for""" additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + """@private""" def to_dict(self) -> Dict[str, Any]: + """@private""" tracks: Union[Unset, List[str]] = UNSET if not isinstance(self.tracks, Unset): tracks = self.tracks @@ -31,6 +33,7 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" d = src_dict.copy() tracks = cast(List[str], d.pop("tracks", UNSET)) @@ -43,6 +46,7 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> Any: diff --git a/jellyfish/_webhook_notifier.py b/jellyfish/_webhook_notifier.py index d4e2d6d..50c0192 100644 --- a/jellyfish/_webhook_notifier.py +++ b/jellyfish/_webhook_notifier.py @@ -3,16 +3,22 @@ notification from jellyfish to notification structs. """ -from typing import Any, Dict +import inspect +from typing import Dict, Union import betterproto -from jellyfish.events import ServerMessage +import jellyfish +from jellyfish.events._protos.jellyfish import ServerMessage +server_messages = tuple(m[0] for m in inspect.getmembers(jellyfish.events, inspect.isclass)) -def receive_json(json: Dict) -> Any: + +def receive_json(json: Dict) -> Union[server_messages]: """ Transform received json notification to adequate notification instance. + + The available notifications are listed in `jellyfish.events` module. """ msg = json["notification"] msg = bytes(msg, "utf-8") diff --git a/jellyfish/_ws_notifier.py b/jellyfish/_ws_notifier.py index eaf25dc..d306aff 100644 --- a/jellyfish/_ws_notifier.py +++ b/jellyfish/_ws_notifier.py @@ -9,12 +9,12 @@ from websockets import client from websockets.exceptions import ConnectionClosed -from jellyfish.events import ( +from jellyfish.events import ServerMessageMetricsReport +from jellyfish.events._protos.jellyfish import ( ServerMessage, ServerMessageAuthenticated, ServerMessageAuthRequest, ServerMessageEventType, - ServerMessageMetricsReport, ServerMessageSubscribeRequest, ServerMessageSubscribeResponse, ) diff --git a/jellyfish/events/__init__.py b/jellyfish/events/__init__.py index 683f9ed..f7b8606 100644 --- a/jellyfish/events/__init__.py +++ b/jellyfish/events/__init__.py @@ -4,11 +4,7 @@ # Exported messages from jellyfish.events._protos.jellyfish import ( - ServerMessage, # noqa: F401 - ServerMessageAuthenticated, # noqa: F401 - ServerMessageAuthRequest, # noqa: F401 ServerMessageComponentCrashed, - ServerMessageEventType, # noqa: F401 ServerMessageHlsPlayable, ServerMessageMetricsReport, ServerMessagePeerConnected, @@ -17,8 +13,6 @@ ServerMessageRoomCrashed, ServerMessageRoomCreated, ServerMessageRoomDeleted, - ServerMessageSubscribeRequest, # noqa: F401 - ServerMessageSubscribeResponse, # noqa: F401 ) __all__ = [ diff --git a/jellyfish/events/_protos/jellyfish/__init__.py b/jellyfish/events/_protos/jellyfish/__init__.py index 8f0ee65..0e254fa 100644 --- a/jellyfish/events/_protos/jellyfish/__init__.py +++ b/jellyfish/events/_protos/jellyfish/__init__.py @@ -37,6 +37,10 @@ class ServerMessage(betterproto.Message): room_deleted: "ServerMessageRoomDeleted" = betterproto.message_field(11, group="content") metrics_report: "ServerMessageMetricsReport" = betterproto.message_field(12, group="content") hls_playable: "ServerMessageHlsPlayable" = betterproto.message_field(13, group="content") + hls_uploaded: "ServerMessageHlsUploaded" = betterproto.message_field(14, group="content") + hls_upload_crashed: "ServerMessageHlsUploadCrashed" = betterproto.message_field( + 15, group="content" + ) @dataclass(eq=False, repr=False) @@ -107,3 +111,13 @@ class ServerMessageMetricsReport(betterproto.Message): class ServerMessageHlsPlayable(betterproto.Message): room_id: str = betterproto.string_field(1) component_id: str = betterproto.string_field(2) + + +@dataclass(eq=False, repr=False) +class ServerMessageHlsUploaded(betterproto.Message): + room_id: str = betterproto.string_field(1) + + +@dataclass(eq=False, repr=False) +class ServerMessageHlsUploadCrashed(betterproto.Message): + room_id: str = betterproto.string_field(1) diff --git a/openapi-python-client-config.yaml b/openapi-python-client-config.yaml index b0cacfb..04b91da 100644 --- a/openapi-python-client-config.yaml +++ b/openapi-python-client-config.yaml @@ -1,2 +1,2 @@ project_name_override: jellyfish -package_name_override: _openapi_client \ No newline at end of file +package_name_override: _openapi_client diff --git a/openapi_templates/model.py.jinja b/openapi_templates/model.py.jinja index 0c16e4e..e6e7c71 100644 --- a/openapi_templates/model.py.jinja +++ b/openapi_templates/model.py.jinja @@ -72,6 +72,7 @@ class {{ class_name }}: {% endfor %} {% if model.additional_properties %} additional_properties: Dict[str, {{ additional_property_type }}] = _attrs_field(init=False, factory=dict) + """@private""" {% endif %} {% macro _to_dict(multipart=False) %} @@ -123,6 +124,7 @@ return field_dict {% endmacro %} def to_dict(self) -> Dict[str, Any]: + """@private""" {% for lazy_import in model.lazy_imports %} {{ lazy_import }} {% endfor %} @@ -135,6 +137,7 @@ return field_dict @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + """@private""" {% for lazy_import in model.lazy_imports %} {{ lazy_import }} {% endfor %} @@ -187,6 +190,7 @@ return field_dict {% if model.additional_properties %} @property def additional_keys(self) -> List[str]: + """@private""" return list(self.additional_properties.keys()) def __getitem__(self, key: str) -> {{ additional_property_type }}: diff --git a/openapi_templates/str_enum.py.jinja b/openapi_templates/str_enum.py.jinja index e28fdfb..9c2a213 100644 --- a/openapi_templates/str_enum.py.jinja +++ b/openapi_templates/str_enum.py.jinja @@ -4,7 +4,6 @@ class {{ enum.class_info.name }}(str, Enum): """{{ enum.description }}""" {% for key, value in enum.values|dictsort(true) %} {{ key }} = "{{ value }}" - """{{ enum.class_info.name }}: {{ value }}""" {% endfor %} def __str__(self) -> str: diff --git a/poetry_scripts.py b/poetry_scripts.py index 1a049d1..2b44856 100644 --- a/poetry_scripts.py +++ b/poetry_scripts.py @@ -34,7 +34,7 @@ def run_linter_fix(): def generate_docs(): check_exit_code( "pdoc \ - --no-include-undocumented \ + --include-undocumented \ --favicon https://logo.swmansion.com/membrane/\?width\=100\&variant\=signetDark\ --logo https://logo.swmansion.com/membrane/\?width\=70\&variant\=signetDark\ -t doc_templates \ diff --git a/protos b/protos index a6f6971..3781848 160000 --- a/protos +++ b/protos @@ -1 +1 @@ -Subproject commit a6f69712da283d13ae8b6e828694b48fce92a9e5 +Subproject commit 3781848239f67a88866f861fa798a8c18384e666 diff --git a/tests/test_recording_api.py b/tests/test_recording_api.py index a906a3e..1b31d4a 100644 --- a/tests/test_recording_api.py +++ b/tests/test_recording_api.py @@ -27,5 +27,5 @@ def test_valid(self, recording_api: RecordingApi): class TestDelete: def test_invalid_recording(self, recording_api: RecordingApi): - with pytest.raises(Exception): + with pytest.raises(RuntimeError): recording_api.delete("invalid-id") From 6d351b968f489e760823c4a2928de0a9f2fb3873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Fri, 15 Dec 2023 16:17:37 +0100 Subject: [PATCH 6/9] Add custom http errors --- README.md | 2 + jellyfish/__init__.py | 7 ++-- jellyfish/_webhook_notifier.py | 4 +- jellyfish/api/__init__.py | 0 jellyfish/api/_base_api.py | 24 +++++++++++ jellyfish/{ => api}/_recording_api.py | 17 +++----- jellyfish/{ => api}/_room_api.py | 57 +++++++++++---------------- jellyfish/errors.py | 49 +++++++++++++++++++++++ openapi_templates/str_enum.py.jinja | 2 +- poetry_scripts.py | 9 +++-- pyproject.toml | 3 +- tests/test_notifier.py | 8 ---- tests/test_recording_api.py | 6 +-- tests/test_room_api.py | 30 ++++++++++---- 14 files changed, 142 insertions(+), 76 deletions(-) create mode 100644 jellyfish/api/__init__.py create mode 100644 jellyfish/api/_base_api.py rename jellyfish/{ => api}/_recording_api.py (63%) rename jellyfish/{ => api}/_room_api.py (67%) create mode 100644 jellyfish/errors.py diff --git a/README.md b/README.md index d70fb6c..3f90fa4 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ component_hls = room_api.add_component(room.id, options=ComponentOptionsHLS()) # ComponentHLS(id='5f062447-a9f7-45ed-8d1b-511f77dc78ae', properties=ComponentPropertiesHLS(low_latency=False, persistent=False, playable=False, subscribe_mode=, target_window_duration=None), type='hls') ``` +All methods in `RoomApi` may raise one of the exceptions deriving from `jellyfish.errors.HTTPError`. They are defined in `jellyfish.errors`. + #### Notifier Create `Notifier` instance diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index 6a4facd..b1be56d 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -5,7 +5,7 @@ # pylint: disable=locally-disabled, no-name-in-module, import-error # Server Messages -from jellyfish import events +from jellyfish import errors, events # Models from jellyfish._openapi_client.models import ( @@ -24,12 +24,12 @@ RoomConfig, RoomConfigVideoCodec, ) -from jellyfish._recording_api import RecordingApi -from jellyfish._room_api import RoomApi # API from jellyfish._webhook_notifier import receive_json from jellyfish._ws_notifier import Notifier +from jellyfish.api._recording_api import RecordingApi +from jellyfish.api._room_api import RoomApi __all__ = [ "RoomApi", @@ -51,6 +51,7 @@ "ComponentOptionsRTSP", "ComponentPropertiesRTSP", "events", + "errors", ] __docformat__ = "restructuredtext" diff --git a/jellyfish/_webhook_notifier.py b/jellyfish/_webhook_notifier.py index 50c0192..5da7b8e 100644 --- a/jellyfish/_webhook_notifier.py +++ b/jellyfish/_webhook_notifier.py @@ -11,10 +11,10 @@ import jellyfish from jellyfish.events._protos.jellyfish import ServerMessage -server_messages = tuple(m[0] for m in inspect.getmembers(jellyfish.events, inspect.isclass)) +SERVER_MESSAGE_TYPES = tuple(m[0] for m in inspect.getmembers(jellyfish.events, inspect.isclass)) -def receive_json(json: Dict) -> Union[server_messages]: +def receive_json(json: Dict) -> Union[SERVER_MESSAGE_TYPES]: """ Transform received json notification to adequate notification instance. diff --git a/jellyfish/api/__init__.py b/jellyfish/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jellyfish/api/_base_api.py b/jellyfish/api/_base_api.py new file mode 100644 index 0000000..0b1a731 --- /dev/null +++ b/jellyfish/api/_base_api.py @@ -0,0 +1,24 @@ +from jellyfish._openapi_client.client import AuthenticatedClient +from jellyfish._openapi_client.models import Error +from jellyfish._openapi_client.types import Response +from jellyfish.errors import HTTPError + + +class BaseApi: + def __init__( + self, + server_address: str = "localhost:5002", + server_api_token: str = "development", + secure: bool = False, + ): + protocol = "https" if secure else "http" + + self.client = AuthenticatedClient(f"{protocol}://{server_address}", token=server_api_token) + + def _request(self, method, **kwargs): + response: Response = method.sync_detailed(client=self.client, **kwargs) + + if isinstance(response.parsed, Error): + raise HTTPError.from_response(response) + + return response.parsed diff --git a/jellyfish/_recording_api.py b/jellyfish/api/_recording_api.py similarity index 63% rename from jellyfish/_recording_api.py rename to jellyfish/api/_recording_api.py index 43466dc..4fe4533 100644 --- a/jellyfish/_recording_api.py +++ b/jellyfish/api/_recording_api.py @@ -2,12 +2,11 @@ RecordingApi used to manage rooms """ -from jellyfish._openapi_client import AuthenticatedClient from jellyfish._openapi_client.api.recording import delete_recording, get_recordings -from jellyfish._openapi_client.models import Error +from jellyfish.api._base_api import BaseApi -class RecordingApi: +class RecordingApi(BaseApi): """Allows for managing recordings""" def __init__( @@ -21,8 +20,9 @@ def __init__( Set secure to `True` for `https` and `False` for `http` connection (default). """ - protocol = "https" if secure else "http" - self._client = AuthenticatedClient(f"{protocol}://{server_address}", token=server_api_token) + super().__init__( + server_address=server_address, server_api_token=server_api_token, secure=secure + ) def get_list(self) -> list: """Returns a list of available recordings""" @@ -33,10 +33,3 @@ def delete(self, recording_id: str): """Deletes recording with given id""" return self._request(delete_recording, recording_id=recording_id) - - def _request(self, method, **kwargs): - resp = method.sync(client=self._client, **kwargs) - if isinstance(resp, Error): - raise RuntimeError(resp.errors) - - return resp diff --git a/jellyfish/_room_api.py b/jellyfish/api/_room_api.py similarity index 67% rename from jellyfish/_room_api.py rename to jellyfish/api/_room_api.py index f0ba3d5..07b71b8 100644 --- a/jellyfish/_room_api.py +++ b/jellyfish/api/_room_api.py @@ -4,18 +4,15 @@ from typing import Literal, Union -from jellyfish._openapi_client import AuthenticatedClient -from jellyfish._openapi_client.api.hls import subscribe_tracks -from jellyfish._openapi_client.api.room import ( - add_component, - add_peer, - create_room, - delete_component, - delete_peer, - delete_room, - get_all_rooms, - get_room, -) +from jellyfish._openapi_client.api.hls import subscribe_tracks as hls_subscribe_tracks +from jellyfish._openapi_client.api.room import add_component as room_add_component +from jellyfish._openapi_client.api.room import add_peer as room_add_peer +from jellyfish._openapi_client.api.room import create_room as room_create_room +from jellyfish._openapi_client.api.room import delete_component as room_delete_component +from jellyfish._openapi_client.api.room import delete_peer as room_delete_peer +from jellyfish._openapi_client.api.room import delete_room as room_delete_room +from jellyfish._openapi_client.api.room import get_all_rooms as room_get_all_rooms +from jellyfish._openapi_client.api.room import get_room as room_get_room from jellyfish._openapi_client.models import ( AddComponentJsonBody, AddPeerJsonBody, @@ -23,7 +20,6 @@ ComponentOptionsHLS, ComponentOptionsRTSP, ComponentRTSP, - Error, Peer, PeerOptionsWebRTC, Room, @@ -31,9 +27,10 @@ RoomConfigVideoCodec, SubscriptionConfig, ) +from jellyfish.api._base_api import BaseApi -class RoomApi: +class RoomApi(BaseApi): """Allows for managing rooms""" def __init__( @@ -46,10 +43,9 @@ def __init__( Create RoomApi instance, providing the jellyfish address and api token. Set secure to `True` for `https` and `False` for `http` connection (default). """ - - protocol = "https" if secure else "http" - - self._client = AuthenticatedClient(f"{protocol}://{server_address}", token=server_api_token) + super().__init__( + server_address=server_address, server_api_token=server_api_token, secure=secure + ) def create_room( self, @@ -77,23 +73,23 @@ def create_room( max_peers=max_peers, video_codec=video_codec, webhook_url=webhook_url ) - resp = self._request(create_room, json_body=room_config) + resp = self._request(room_create_room, json_body=room_config) return (resp.data.jellyfish_address, resp.data.room) def delete_room(self, room_id: str) -> None: """Deletes a room""" - return self._request(delete_room, room_id=room_id) + return self._request(room_delete_room, room_id=room_id) def get_all_rooms(self) -> list: """Returns list of all rooms""" - return self._request(get_all_rooms).data + return self._request(room_get_all_rooms).data def get_room(self, room_id: str) -> Room: """Returns room with the given id""" - return self._request(get_room, room_id=room_id).data + return self._request(room_get_room, room_id=room_id).data def add_peer(self, room_id: str, options: PeerOptionsWebRTC) -> (str, Peer): """ @@ -108,13 +104,13 @@ def add_peer(self, room_id: str, options: PeerOptionsWebRTC) -> (str, Peer): peer_type = "webrtc" json_body = AddPeerJsonBody(type=peer_type, options=options) - resp = self._request(add_peer, room_id=room_id, json_body=json_body) + resp = self._request(room_add_peer, room_id=room_id, json_body=json_body) return (resp.data.token, resp.data.peer) def delete_peer(self, room_id: str, peer_id: str) -> None: """Deletes peer""" - return self._request(delete_peer, id=peer_id, room_id=room_id) + return self._request(room_delete_peer, id=peer_id, room_id=room_id) def add_component( self, room_id: str, options: Union[ComponentOptionsHLS, ComponentOptionsRTSP] @@ -130,23 +126,16 @@ def add_component( json_body = AddComponentJsonBody(type=component_type, options=options) - return self._request(add_component, room_id=room_id, json_body=json_body).data + return self._request(room_add_component, room_id=room_id, json_body=json_body).data def delete_component(self, room_id: str, component_id: str) -> None: """Deletes component""" - return self._request(delete_component, id=component_id, room_id=room_id) + return self._request(room_delete_component, id=component_id, room_id=room_id) def hls_subscribe(self, room_id: str, tracks: list): """subscribes hls component for tracks""" subscription_config = SubscriptionConfig(tracks=tracks) - return self._request(subscribe_tracks, room_id=room_id, json_body=subscription_config) - - def _request(self, method, **kwargs): - resp = method.sync(client=self._client, **kwargs) - if isinstance(resp, Error): - raise RuntimeError(resp.errors) - - return resp + return self._request(hls_subscribe_tracks, room_id=room_id, json_body=subscription_config) diff --git a/jellyfish/errors.py b/jellyfish/errors.py new file mode 100644 index 0000000..7b4c3cc --- /dev/null +++ b/jellyfish/errors.py @@ -0,0 +1,49 @@ +from http import HTTPStatus + +from jellyfish._openapi_client.types import Response + + +class HTTPError(Exception): + """""" + + @staticmethod + def from_response(response: Response): + """@private""" + errors = response.parsed.errors + print("resp errors", errors) + + if response.status_code == HTTPStatus.BAD_REQUEST: + return BadRequestError(errors) + + if response.status_code == HTTPStatus.UNAUTHORIZED: + return UnauthorizedError(errors) + + if response.status_code == HTTPStatus.NOT_FOUND: + return NotFoundError(errors) + + if response.status_code == HTTPStatus.SERVICE_UNAVAILABLE: + return ServiceUnavailableError(errors) + + +class BadRequestError(HTTPError): + def __init__(self, errors): + """@private""" + super().__init__(errors) + + +class UnauthorizedError(HTTPError): + def __init__(self, errors): + """@private""" + super().__init__(errors) + + +class NotFoundError(HTTPError): + def __init__(self, errors): + """@private""" + super().__init__(errors) + + +class ServiceUnavailableError(HTTPError): + def __init__(self, errors): + """@private""" + super().__init__(errors) diff --git a/openapi_templates/str_enum.py.jinja b/openapi_templates/str_enum.py.jinja index 9c2a213..87581e9 100644 --- a/openapi_templates/str_enum.py.jinja +++ b/openapi_templates/str_enum.py.jinja @@ -7,4 +7,4 @@ class {{ enum.class_info.name }}(str, Enum): {% endfor %} def __str__(self) -> str: - return str(self.value) \ No newline at end of file + return str(self.value) diff --git a/poetry_scripts.py b/poetry_scripts.py index 2b44856..24aa3d4 100644 --- a/poetry_scripts.py +++ b/poetry_scripts.py @@ -3,6 +3,8 @@ import sys from pathlib import Path +# ruff: noqa: E501 + def check_exit_code(command): command_exit_code = os.system(command) @@ -14,7 +16,8 @@ def run_tests(): check_exit_code("docker rm -f jellyfish") check_exit_code("docker compose -f docker-compose-test.yaml pull") check_exit_code( - "docker compose -f docker-compose-test.yaml up --remove-orphans test --exit-code-from test" + "docker compose -f docker-compose-test.yaml up --remove-orphans test \ + --exit-code-from test" ) check_exit_code("docker compose -f docker-compose-test.yaml down") @@ -55,9 +58,9 @@ def generate_docs(): f.rename(f.with_suffix(".md")) -def generate_client(): +def update_client(): check_exit_code( - "openapi-python-client generate\ + "openapi-python-client update\ --url https://raw.githubusercontent.com/jellyfish-dev/jellyfish/main/openapi.yaml \ --config openapi-python-client-config.yaml \ --custom-template-path=openapi_templates" diff --git a/pyproject.toml b/pyproject.toml index 4edde73..5566283 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ httpx = ">=0.20.0,<0.26.0" attrs = ">=21.3.0" [tool.poetry.group.dev.dependencies] -pylint = "^2.17.6" betterproto = { version = "= 2.0.0b6", extras = ["compiler"] } pdoc = "^14.1.0" mkdocs = "^1.5.3" @@ -44,7 +43,7 @@ format = "poetry_scripts:run_formatter" lint = "poetry_scripts:run_linter" fix_lint = "poetry_scripts:run_linter_fix" generate_docs = "poetry_scripts:generate_docs" -generate_client = "poetry_scripts:generate_client" +update_client = "poetry_scripts:update_client" [tool.ruff] select = ["F", "I"] diff --git a/tests/test_notifier.py b/tests/test_notifier.py index cddb0c4..ac15b3e 100644 --- a/tests/test_notifier.py +++ b/tests/test_notifier.py @@ -82,14 +82,6 @@ def room_api(): def notifier(): notifier = Notifier(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) - @notifier.on_server_notification - def handle_notification(_server_notification): - pass - - @notifier.on_metrics - def handle_metrics(_metrics_report): - pass - return notifier diff --git a/tests/test_recording_api.py b/tests/test_recording_api.py index 1b31d4a..b4f18c0 100644 --- a/tests/test_recording_api.py +++ b/tests/test_recording_api.py @@ -5,9 +5,7 @@ import pytest from jellyfish import RecordingApi - -# from jellyfish import NotFoundException - +from jellyfish.errors import NotFoundError HOST = "jellyfish" if os.getenv("DOCKER_TEST") == "TRUE" else "localhost" SERVER_ADDRESS = f"{HOST}:5002" @@ -27,5 +25,5 @@ def test_valid(self, recording_api: RecordingApi): class TestDelete: def test_invalid_recording(self, recording_api: RecordingApi): - with pytest.raises(RuntimeError): + with pytest.raises(NotFoundError): recording_api.delete("invalid-id") diff --git a/tests/test_room_api.py b/tests/test_room_api.py index 794ad89..b06f4a1 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -22,6 +22,12 @@ RoomConfig, RoomConfigVideoCodec, ) +from jellyfish.errors import ( + BadRequestError, + NotFoundError, + ServiceUnavailableError, + UnauthorizedError, +) HOST = "jellyfish" if os.getenv("DOCKER_TEST") == "TRUE" else "localhost" SERVER_ADDRESS = f"{HOST}:5002" @@ -40,7 +46,7 @@ class TestAuthentication: def test_invalid_token(self): room_api = RoomApi(server_address=SERVER_ADDRESS, server_api_token="invalid") - with pytest.raises(RuntimeError): + with pytest.raises(UnauthorizedError): room_api.create_room() def test_valid_token(self): @@ -96,7 +102,7 @@ def test_valid_params(self, room_api): assert room in room_api.get_all_rooms() def test_invalid_max_peers(self, room_api): - with pytest.raises(RuntimeError): + with pytest.raises(BadRequestError): room_api.create_room(max_peers="10", video_codec=CODEC_H264, webhook_url=None) def test_invalid_video_codec(self, room_api): @@ -112,7 +118,7 @@ def test_valid(self, room_api): assert room not in room_api.get_all_rooms() def test_invalid(self, room_api): - with pytest.raises(RuntimeError): + with pytest.raises(NotFoundError): room_api.delete_room("invalid_id") @@ -137,7 +143,7 @@ def test_valid(self, room_api: RoomApi): ) == room_api.get_room(room.id) def test_invalid(self, room_api: RoomApi): - with pytest.raises(RuntimeError): + with pytest.raises(NotFoundError): room_api.get_room("invalid_id") @@ -192,7 +198,7 @@ def test_valid_component(self, room_api: RoomApi): def test_invalid_component(self, room_api: RoomApi): _, room = room_api.create_room() - with pytest.raises(RuntimeError): + with pytest.raises(NotFoundError): room_api.delete_component(room.id, "invalid_id") @@ -208,7 +214,7 @@ def test_valid_subscription(self, room_api: RoomApi): def test_invalid_subscription(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) _ = room_api.add_component(room.id, options=HLS_OPTIONS) - with pytest.raises(RuntimeError): + with pytest.raises(BadRequestError): room_api.hls_subscribe(room.id, ["track-id"]) @@ -233,6 +239,16 @@ def test_default_options(self, room_api: RoomApi): self._assert_peer_created(room_api, peer, room.id) + def test_peer_limit_reached(self, room_api: RoomApi): + _, room = room_api.create_room(max_peers=1) + + _token, peer = room_api.add_peer(room.id, options=PeerOptionsWebRTC()) + + self._assert_peer_created(room_api, peer, room.id) + + with pytest.raises(ServiceUnavailableError): + room_api.add_peer(room.id, options=PeerOptionsWebRTC()) + class TestDeletePeer: def test_valid(self, room_api: RoomApi): @@ -246,5 +262,5 @@ def test_valid(self, room_api: RoomApi): def test_invalid(self, room_api: RoomApi): _, room = room_api.create_room() - with pytest.raises(RuntimeError): + with pytest.raises(NotFoundError): room_api.delete_peer(room.id, peer_id="invalid_peer_id") From 23125ee280a2c8c91e5b1eb7527e497637ab7e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Sun, 17 Dec 2023 20:59:24 +0100 Subject: [PATCH 7/9] Update comment --- jellyfish/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jellyfish/__init__.py b/jellyfish/__init__.py index b1be56d..4d51a02 100644 --- a/jellyfish/__init__.py +++ b/jellyfish/__init__.py @@ -4,7 +4,7 @@ # pylint: disable=locally-disabled, no-name-in-module, import-error -# Server Messages +# Exceptions and Server Messages from jellyfish import errors, events # Models @@ -53,5 +53,4 @@ "events", "errors", ] - __docformat__ = "restructuredtext" From 14c0ea596e0908001e876d6ef262c34ef72d3495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Mon, 18 Dec 2023 18:47:30 +0100 Subject: [PATCH 8/9] Fix docs warning --- jellyfish/_webhook_notifier.py | 8 ++------ poetry_scripts.py | 5 ++--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/jellyfish/_webhook_notifier.py b/jellyfish/_webhook_notifier.py index 5da7b8e..020f959 100644 --- a/jellyfish/_webhook_notifier.py +++ b/jellyfish/_webhook_notifier.py @@ -3,18 +3,14 @@ notification from jellyfish to notification structs. """ -import inspect -from typing import Dict, Union +from typing import Dict import betterproto -import jellyfish from jellyfish.events._protos.jellyfish import ServerMessage -SERVER_MESSAGE_TYPES = tuple(m[0] for m in inspect.getmembers(jellyfish.events, inspect.isclass)) - -def receive_json(json: Dict) -> Union[SERVER_MESSAGE_TYPES]: +def receive_json(json: Dict) -> betterproto.Message: """ Transform received json notification to adequate notification instance. diff --git a/poetry_scripts.py b/poetry_scripts.py index 24aa3d4..fc48bd3 100644 --- a/poetry_scripts.py +++ b/poetry_scripts.py @@ -3,8 +3,6 @@ import sys from pathlib import Path -# ruff: noqa: E501 - def check_exit_code(command): command_exit_code = os.system(command) @@ -61,7 +59,8 @@ def generate_docs(): def update_client(): check_exit_code( "openapi-python-client update\ - --url https://raw.githubusercontent.com/jellyfish-dev/jellyfish/main/openapi.yaml \ + --url https://raw.githubusercontent.com/jellyfish-dev/" + "jellyfish/main/openapi.yaml \ --config openapi-python-client-config.yaml \ --custom-template-path=openapi_templates" ) From fbbef8e7ef4a16f40f38e22b225c8ea1879a92f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Ro=C5=BCnawski?= Date: Tue, 19 Dec 2023 16:39:35 +0100 Subject: [PATCH 9/9] Default line length of 88 --- jellyfish/_openapi_client/client.py | 4 +- .../models/add_component_json_body.py | 16 ++++++-- .../models/component_details_response.py | 4 +- .../models/component_options_hls.py | 4 +- .../models/component_properties_hls.py | 4 +- .../models/room_create_details_response.py | 4 +- jellyfish/_ws_notifier.py | 8 +++- jellyfish/api/_base_api.py | 4 +- jellyfish/api/_recording_api.py | 4 +- jellyfish/api/_room_api.py | 24 +++++++---- .../events/_protos/jellyfish/__init__.py | 40 ++++++++++++++----- pyproject.toml | 1 - tests/support/protos/jellyfish/__init__.py | 8 +++- tests/test_notifier.py | 24 ++++++++--- tests/test_recording_api.py | 4 +- tests/test_room_api.py | 24 ++++++++--- 16 files changed, 130 insertions(+), 47 deletions(-) diff --git a/jellyfish/_openapi_client/client.py b/jellyfish/_openapi_client/client.py index 81c0139..0a07559 100644 --- a/jellyfish/_openapi_client/client.py +++ b/jellyfish/_openapi_client/client.py @@ -237,7 +237,9 @@ def __exit__(self, *args: Any, **kwargs: Any) -> None: """Exit a context manager for internal httpx.Client (see httpx docs)""" self.get_httpx_client().__exit__(*args, **kwargs) - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + def set_async_httpx_client( + self, async_client: httpx.AsyncClient + ) -> "AuthenticatedClient": """Manually the underlying httpx.AsyncClient **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. diff --git a/jellyfish/_openapi_client/models/add_component_json_body.py b/jellyfish/_openapi_client/models/add_component_json_body.py index 153b23e..82c7699 100644 --- a/jellyfish/_openapi_client/models/add_component_json_body.py +++ b/jellyfish/_openapi_client/models/add_component_json_body.py @@ -70,13 +70,17 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: def _parse_options( data: object, - ) -> Union["ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset]: + ) -> Union[ + "ComponentOptionsFile", "ComponentOptionsHLS", "ComponentOptionsRTSP", Unset + ]: if isinstance(data, Unset): return data try: if not isinstance(data, dict): raise TypeError() - componentsschemas_component_options_type_0 = ComponentOptionsHLS.from_dict(data) + componentsschemas_component_options_type_0 = ( + ComponentOptionsHLS.from_dict(data) + ) return componentsschemas_component_options_type_0 except: # noqa: E722 @@ -84,14 +88,18 @@ def _parse_options( try: if not isinstance(data, dict): raise TypeError() - componentsschemas_component_options_type_1 = ComponentOptionsRTSP.from_dict(data) + componentsschemas_component_options_type_1 = ( + ComponentOptionsRTSP.from_dict(data) + ) return componentsschemas_component_options_type_1 except: # noqa: E722 pass if not isinstance(data, dict): raise TypeError() - componentsschemas_component_options_type_2 = ComponentOptionsFile.from_dict(data) + componentsschemas_component_options_type_2 = ComponentOptionsFile.from_dict( + data + ) return componentsschemas_component_options_type_2 diff --git a/jellyfish/_openapi_client/models/component_details_response.py b/jellyfish/_openapi_client/models/component_details_response.py index 313d958..959e0bc 100644 --- a/jellyfish/_openapi_client/models/component_details_response.py +++ b/jellyfish/_openapi_client/models/component_details_response.py @@ -56,7 +56,9 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() - def _parse_data(data: object) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: + def _parse_data( + data: object, + ) -> Union["ComponentFile", "ComponentHLS", "ComponentRTSP"]: try: if not isinstance(data, dict): raise TypeError() diff --git a/jellyfish/_openapi_client/models/component_options_hls.py b/jellyfish/_openapi_client/models/component_options_hls.py index 6b4bd00..4142984 100644 --- a/jellyfish/_openapi_client/models/component_options_hls.py +++ b/jellyfish/_openapi_client/models/component_options_hls.py @@ -3,7 +3,9 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -from ..models.component_options_hls_subscribe_mode import ComponentOptionsHLSSubscribeMode +from ..models.component_options_hls_subscribe_mode import ( + ComponentOptionsHLSSubscribeMode, +) from ..types import UNSET, Unset if TYPE_CHECKING: diff --git a/jellyfish/_openapi_client/models/component_properties_hls.py b/jellyfish/_openapi_client/models/component_properties_hls.py index 34241e5..6575ca2 100644 --- a/jellyfish/_openapi_client/models/component_properties_hls.py +++ b/jellyfish/_openapi_client/models/component_properties_hls.py @@ -3,7 +3,9 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field -from ..models.component_properties_hls_subscribe_mode import ComponentPropertiesHLSSubscribeMode +from ..models.component_properties_hls_subscribe_mode import ( + ComponentPropertiesHLSSubscribeMode, +) T = TypeVar("T", bound="ComponentPropertiesHLS") diff --git a/jellyfish/_openapi_client/models/room_create_details_response.py b/jellyfish/_openapi_client/models/room_create_details_response.py index fe88790..8194c0e 100644 --- a/jellyfish/_openapi_client/models/room_create_details_response.py +++ b/jellyfish/_openapi_client/models/room_create_details_response.py @@ -36,7 +36,9 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: """@private""" - from ..models.room_create_details_response_data import RoomCreateDetailsResponseData + from ..models.room_create_details_response_data import ( + RoomCreateDetailsResponseData, + ) d = src_dict.copy() data = RoomCreateDetailsResponseData.from_dict(d.pop("data")) diff --git a/jellyfish/_ws_notifier.py b/jellyfish/_ws_notifier.py index d306aff..941c730 100644 --- a/jellyfish/_ws_notifier.py +++ b/jellyfish/_ws_notifier.py @@ -86,7 +86,9 @@ async def connect(self): ) if self._metrics_handler: - await self._subscribe_event(event=ServerMessageEventType.EVENT_TYPE_METRICS) + await self._subscribe_event( + event=ServerMessageEventType.EVENT_TYPE_METRICS + ) self._ready = True if self._ready_event: @@ -111,7 +113,9 @@ async def wait_ready(self) -> True: await self._ready_event.wait() async def _authenticate(self): - msg = ServerMessage(auth_request=ServerMessageAuthRequest(token=self._server_api_token)) + msg = ServerMessage( + auth_request=ServerMessageAuthRequest(token=self._server_api_token) + ) await self._websocket.send(bytes(msg)) try: diff --git a/jellyfish/api/_base_api.py b/jellyfish/api/_base_api.py index 0b1a731..9c0369b 100644 --- a/jellyfish/api/_base_api.py +++ b/jellyfish/api/_base_api.py @@ -13,7 +13,9 @@ def __init__( ): protocol = "https" if secure else "http" - self.client = AuthenticatedClient(f"{protocol}://{server_address}", token=server_api_token) + self.client = AuthenticatedClient( + f"{protocol}://{server_address}", token=server_api_token + ) def _request(self, method, **kwargs): response: Response = method.sync_detailed(client=self.client, **kwargs) diff --git a/jellyfish/api/_recording_api.py b/jellyfish/api/_recording_api.py index 4fe4533..e765a0b 100644 --- a/jellyfish/api/_recording_api.py +++ b/jellyfish/api/_recording_api.py @@ -21,7 +21,9 @@ def __init__( """ super().__init__( - server_address=server_address, server_api_token=server_api_token, secure=secure + server_address=server_address, + server_api_token=server_api_token, + secure=secure, ) def get_list(self) -> list: diff --git a/jellyfish/api/_room_api.py b/jellyfish/api/_room_api.py index 07b71b8..7d6555a 100644 --- a/jellyfish/api/_room_api.py +++ b/jellyfish/api/_room_api.py @@ -44,7 +44,9 @@ def __init__( Set secure to `True` for `https` and `False` for `http` connection (default). """ super().__init__( - server_address=server_address, server_api_token=server_api_token, secure=secure + server_address=server_address, + server_api_token=server_api_token, + secure=secure, ) def create_room( @@ -60,8 +62,8 @@ def create_room( in which the room has been created and the created `Room` The returned address may be different from the current `RoomApi` instance. - In such case, a new `RoomApi` instance has to be created using the returned address - in order to interact with the room. + In such case, a new `RoomApi` instance has to be created using + the returned address in order to interact with the room. """ if video_codec is not None: @@ -97,8 +99,8 @@ def add_peer(self, room_id: str, options: PeerOptionsWebRTC) -> (str, Peer): Currently only `webrtc` peer is supported - Returns a tuple (`peer_token`, `Peer`) - the token needed by Peer to authenticate - to Jellyfish and the new `Peer` + Returns a tuple (`peer_token`, `Peer`) - the token needed by Peer + to authenticate to Jellyfish and the new `Peer` """ peer_type = "webrtc" @@ -122,11 +124,15 @@ def add_component( elif isinstance(options, ComponentOptionsRTSP): component_type = "rtsp" else: - raise ValueError("options must be either ComponentOptionsHLS or ComponentOptionsRTSP") + raise ValueError( + "options must be either ComponentOptionsHLS or ComponentOptionsRTSP" + ) json_body = AddComponentJsonBody(type=component_type, options=options) - return self._request(room_add_component, room_id=room_id, json_body=json_body).data + return self._request( + room_add_component, room_id=room_id, json_body=json_body + ).data def delete_component(self, room_id: str, component_id: str) -> None: """Deletes component""" @@ -138,4 +144,6 @@ def hls_subscribe(self, room_id: str, tracks: list): subscription_config = SubscriptionConfig(tracks=tracks) - return self._request(hls_subscribe_tracks, room_id=room_id, json_body=subscription_config) + return self._request( + hls_subscribe_tracks, room_id=room_id, json_body=subscription_config + ) diff --git a/jellyfish/events/_protos/jellyfish/__init__.py b/jellyfish/events/_protos/jellyfish/__init__.py index 0e254fa..60b5403 100644 --- a/jellyfish/events/_protos/jellyfish/__init__.py +++ b/jellyfish/events/_protos/jellyfish/__init__.py @@ -16,28 +16,48 @@ class ServerMessageEventType(betterproto.Enum): @dataclass(eq=False, repr=False) class ServerMessage(betterproto.Message): - room_crashed: "ServerMessageRoomCrashed" = betterproto.message_field(1, group="content") - peer_connected: "ServerMessagePeerConnected" = betterproto.message_field(2, group="content") + room_crashed: "ServerMessageRoomCrashed" = betterproto.message_field( + 1, group="content" + ) + peer_connected: "ServerMessagePeerConnected" = betterproto.message_field( + 2, group="content" + ) peer_disconnected: "ServerMessagePeerDisconnected" = betterproto.message_field( 3, group="content" ) - peer_crashed: "ServerMessagePeerCrashed" = betterproto.message_field(4, group="content") + peer_crashed: "ServerMessagePeerCrashed" = betterproto.message_field( + 4, group="content" + ) component_crashed: "ServerMessageComponentCrashed" = betterproto.message_field( 5, group="content" ) - authenticated: "ServerMessageAuthenticated" = betterproto.message_field(6, group="content") - auth_request: "ServerMessageAuthRequest" = betterproto.message_field(7, group="content") + authenticated: "ServerMessageAuthenticated" = betterproto.message_field( + 6, group="content" + ) + auth_request: "ServerMessageAuthRequest" = betterproto.message_field( + 7, group="content" + ) subscribe_request: "ServerMessageSubscribeRequest" = betterproto.message_field( 8, group="content" ) subscribe_response: "ServerMessageSubscribeResponse" = betterproto.message_field( 9, group="content" ) - room_created: "ServerMessageRoomCreated" = betterproto.message_field(10, group="content") - room_deleted: "ServerMessageRoomDeleted" = betterproto.message_field(11, group="content") - metrics_report: "ServerMessageMetricsReport" = betterproto.message_field(12, group="content") - hls_playable: "ServerMessageHlsPlayable" = betterproto.message_field(13, group="content") - hls_uploaded: "ServerMessageHlsUploaded" = betterproto.message_field(14, group="content") + room_created: "ServerMessageRoomCreated" = betterproto.message_field( + 10, group="content" + ) + room_deleted: "ServerMessageRoomDeleted" = betterproto.message_field( + 11, group="content" + ) + metrics_report: "ServerMessageMetricsReport" = betterproto.message_field( + 12, group="content" + ) + hls_playable: "ServerMessageHlsPlayable" = betterproto.message_field( + 13, group="content" + ) + hls_uploaded: "ServerMessageHlsUploaded" = betterproto.message_field( + 14, group="content" + ) hls_upload_crashed: "ServerMessageHlsUploadCrashed" = betterproto.message_field( 15, group="content" ) diff --git a/pyproject.toml b/pyproject.toml index 5566283..14d7eef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,6 @@ update_client = "poetry_scripts:update_client" [tool.ruff] select = ["F", "I"] -line-length = 100 [tool.ruff.lint] select = ["F", "I", "E"] diff --git a/tests/support/protos/jellyfish/__init__.py b/tests/support/protos/jellyfish/__init__.py index 31b8bd2..c72002b 100644 --- a/tests/support/protos/jellyfish/__init__.py +++ b/tests/support/protos/jellyfish/__init__.py @@ -10,8 +10,12 @@ @dataclass(eq=False, repr=False) class PeerMessage(betterproto.Message): - authenticated: "PeerMessageAuthenticated" = betterproto.message_field(1, group="content") - auth_request: "PeerMessageAuthRequest" = betterproto.message_field(2, group="content") + authenticated: "PeerMessageAuthenticated" = betterproto.message_field( + 1, group="content" + ) + auth_request: "PeerMessageAuthRequest" = betterproto.message_field( + 2, group="content" + ) media_event: "PeerMessageMediaEvent" = betterproto.message_field(3, group="content") diff --git a/tests/test_notifier.py b/tests/test_notifier.py index ac15b3e..3b1a8a3 100644 --- a/tests/test_notifier.py +++ b/tests/test_notifier.py @@ -54,7 +54,9 @@ def start_server(): class TestConnectingToServer: @pytest.mark.asyncio async def test_valid_credentials(self): - notifier = Notifier(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) + notifier = Notifier( + server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN + ) notifier_task = asyncio.create_task(notifier.connect()) await notifier.wait_ready() @@ -65,7 +67,9 @@ async def test_valid_credentials(self): @pytest.mark.asyncio async def test_invalid_credentials(self): - notifier = Notifier(server_address=SERVER_ADDRESS, server_api_token="wrong_token") + notifier = Notifier( + server_address=SERVER_ADDRESS, server_api_token="wrong_token" + ) task = asyncio.create_task(notifier.connect()) @@ -80,7 +84,9 @@ def room_api(): @pytest.fixture def notifier(): - notifier = Notifier(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) + notifier = Notifier( + server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN + ) return notifier @@ -105,7 +111,9 @@ async def test_room_created_deleted(self, room_api: RoomApi, notifier: Notifier) self.assert_event(event) @pytest.mark.asyncio - async def test_peer_connected_disconnected(self, room_api: RoomApi, notifier: Notifier): + async def test_peer_connected_disconnected( + self, room_api: RoomApi, notifier: Notifier + ): event_checks = [ ServerMessageRoomCreated, ServerMessagePeerConnected, @@ -138,7 +146,9 @@ async def test_peer_connected_disconnected(self, room_api: RoomApi, notifier: No self.assert_event(event) @pytest.mark.asyncio - async def test_peer_connected_room_deleted(self, room_api: RoomApi, notifier: Notifier): + async def test_peer_connected_room_deleted( + self, room_api: RoomApi, notifier: Notifier + ): event_checks = [ ServerMessageRoomCreated, ServerMessagePeerConnected, @@ -182,7 +192,9 @@ async def test_metrics_with_one_peer(self, room_api: RoomApi, notifier: Notifier await peer_socket.wait_ready() - assert_task = asyncio.create_task(assert_metrics(notifier, [ServerMessageMetricsReport])) + assert_task = asyncio.create_task( + assert_metrics(notifier, [ServerMessageMetricsReport]) + ) notifier_task = asyncio.create_task(notifier.connect()) await assert_task diff --git a/tests/test_recording_api.py b/tests/test_recording_api.py index b4f18c0..6993b6f 100644 --- a/tests/test_recording_api.py +++ b/tests/test_recording_api.py @@ -14,7 +14,9 @@ @pytest.fixture def recording_api(): - return RecordingApi(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) + return RecordingApi( + server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN + ) class TestGetList: diff --git a/tests/test_room_api.py b/tests/test_room_api.py index b06f4a1..773e208 100644 --- a/tests/test_room_api.py +++ b/tests/test_room_api.py @@ -50,7 +50,9 @@ def test_invalid_token(self): room_api.create_room() def test_valid_token(self): - room_api = RoomApi(server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN) + room_api = RoomApi( + server_address=SERVER_ADDRESS, server_api_token=SERVER_API_TOKEN + ) _, room = room_api.create_room() @@ -94,7 +96,9 @@ def test_valid_params(self, room_api): assert room == Room( components=[], config=RoomConfig( - max_peers=MAX_PEERS, video_codec=RoomConfigVideoCodec(CODEC_H264), webhook_url=None + max_peers=MAX_PEERS, + video_codec=RoomConfigVideoCodec(CODEC_H264), + webhook_url=None, ), id=room.id, peers=[], @@ -103,7 +107,9 @@ def test_valid_params(self, room_api): def test_invalid_max_peers(self, room_api): with pytest.raises(BadRequestError): - room_api.create_room(max_peers="10", video_codec=CODEC_H264, webhook_url=None) + room_api.create_room( + max_peers="10", video_codec=CODEC_H264, webhook_url=None + ) def test_invalid_video_codec(self, room_api): with pytest.raises(ValueError): @@ -207,7 +213,9 @@ def test_valid_subscription(self, room_api: RoomApi): _, room = room_api.create_room(video_codec=CODEC_H264) _ = room_api.add_component( room.id, - options=ComponentOptionsHLS(subscribe_mode=ComponentOptionsHLSSubscribeMode("manual")), + options=ComponentOptionsHLS( + subscribe_mode=ComponentOptionsHLSSubscribeMode("manual") + ), ) assert room_api.hls_subscribe(room.id, ["track-id"]) is None @@ -228,7 +236,9 @@ def _assert_peer_created(self, room_api, webrtc_peer, room_id): def test_with_specified_options(self, room_api: RoomApi): _, room = room_api.create_room() - _token, peer = room_api.add_peer(room.id, options=PeerOptionsWebRTC(enable_simulcast=True)) + _token, peer = room_api.add_peer( + room.id, options=PeerOptionsWebRTC(enable_simulcast=True) + ) self._assert_peer_created(room_api, peer, room.id) @@ -253,7 +263,9 @@ def test_peer_limit_reached(self, room_api: RoomApi): class TestDeletePeer: def test_valid(self, room_api: RoomApi): _, room = room_api.create_room() - _, peer = room_api.add_peer(room.id, options=PeerOptionsWebRTC(enable_simulcast=True)) + _, peer = room_api.add_peer( + room.id, options=PeerOptionsWebRTC(enable_simulcast=True) + ) room_api.delete_peer(room.id, peer.id)