From 8da05f9fe1232303d9a9b02abfe61090d6bd549a Mon Sep 17 00:00:00 2001 From: p1003 Date: Wed, 10 Dec 2025 15:05:32 +0100 Subject: [PATCH 1/7] update _fishjam_client docstrings --- fishjam/api/_fishjam_client.py | 153 +++++++++++++++++++++++++++------ 1 file changed, 128 insertions(+), 25 deletions(-) diff --git a/fishjam/api/_fishjam_client.py b/fishjam/api/_fishjam_client.py index 626403b..f5104a6 100644 --- a/fishjam/api/_fishjam_client.py +++ b/fishjam/api/_fishjam_client.py @@ -51,7 +51,13 @@ @dataclass class Room: - """Description of the room state""" + """Description of the room state. + + Attributes: + config: Room configuration. + id: Room ID. + peers: List of all peers. + """ config: RoomConfig """Room configuration""" @@ -63,7 +69,15 @@ class Room: @dataclass class RoomOptions: - """Description of a room options""" + """Description of a room options. + + Attributes: + max_peers: Maximum amount of peers allowed into the room. + video_codec: Enforces video codec for each peer in the room. + webhook_url: URL where Fishjam notifications will be sent. + room_type: The use-case of the room. If not provided, this defaults to conference. + public: True if livestream viewers can omit specifying a token. + """ max_peers: int | None = None """Maximum amount of peers allowed into the room""" @@ -86,7 +100,13 @@ class RoomOptions: @dataclass class PeerOptions: - """Options specific to a WebRTC Peer""" + """Options specific to a WebRTC Peer. + + Attributes: + enable_simulcast: Enables the peer to use simulcast. + metadata: Peer metadata. + subscribe_mode: Configuration of peer's subscribing policy. + """ enable_simulcast: bool = True """Enables the peer to use simulcast""" @@ -98,7 +118,12 @@ class PeerOptions: @dataclass class AgentOutputOptions: - """Options of the desired format of audio tracks going from Fishjam to the agent.""" + """Options of the desired format of audio tracks going from Fishjam to the agent. + + Attributes: + audio_format: The format of the audio stream (e.g., 'pcm16'). + audio_sample_rate: The sample rate of the audio stream. + """ audio_format: Literal["pcm16"] = "pcm16" audio_sample_rate: Literal[16000, 24000] = 16000 @@ -106,7 +131,12 @@ class AgentOutputOptions: @dataclass class AgentOptions: - """Options specific to a WebRTC Peer""" + """Options specific to a WebRTC Peer. + + Attributes: + output: Configuration for the agent's output options. + subscribe_mode: Configuration of peer's subscribing policy. + """ output: AgentOutputOptions = field(default_factory=AgentOutputOptions) @@ -114,15 +144,18 @@ class AgentOptions: class FishjamClient(Client): - """Allows for managing rooms""" + """Allows for managing rooms.""" def __init__( self, fishjam_id: str, management_token: str, ): - """ - Create a FishjamClient instance, providing the fishjam id and management token. + """Create a FishjamClient instance. + + Args: + fishjam_id: The unique identifier for the Fishjam instance. + management_token: The token used for authenticating management operations. """ super().__init__(fishjam_id=fishjam_id, management_token=management_token) @@ -131,13 +164,16 @@ def create_peer( room_id: str, options: PeerOptions | None = None, ) -> tuple[Peer, str]: - """ - Creates peer in the room + """Creates a peer in the room. - Returns a tuple (`Peer`, `PeerToken`) - the token is needed by Peer - to authenticate to Fishjam. + Args: + room_id: The ID of the room where the peer will be created. + options: Configuration options for the peer. Defaults to None. - The possible options to pass for peer are `PeerOptions`. + Returns: + A tuple containing: + - Peer: The created peer object. + - str: The peer token needed to authenticate to Fishjam. """ options = options or PeerOptions() @@ -157,6 +193,15 @@ def create_peer( return (resp.data.peer, resp.data.token) def create_agent(self, room_id: str, options: AgentOptions | None = None): + """Creates an agent in the room. + + Args: + room_id: The ID of the room where the agent will be created. + options: Configuration options for the agent. Defaults to None. + + Returns: + Agent: The created agent instance initialized with peer ID, room ID, token, and Fishjam URL. + """ options = options or AgentOptions() body = AddPeerBody( type_=PeerType.AGENT, @@ -181,9 +226,13 @@ def create_agent(self, room_id: str, options: AgentOptions | None = None): return Agent(resp.data.peer.id, room_id, resp.data.token, self._fishjam_url) def create_room(self, options: RoomOptions | None = None) -> Room: - """ - Creates a new room - Returns the created `Room` + """Creates a new room. + + Args: + options: Configuration options for the room. Defaults to None. + + Returns: + Room: The created Room object. """ options = options or RoomOptions() @@ -207,7 +256,11 @@ def create_room(self, options: RoomOptions | None = None) -> Room: return Room(config=room.config, id=room.id, peers=room.peers) def get_all_rooms(self) -> list[Room]: - """Returns list of all rooms""" + """Returns list of all rooms. + + Returns: + list[Room]: A list of all available Room objects. + """ rooms = cast(RoomsListingResponse, self._request(room_get_all_rooms)).data @@ -216,7 +269,14 @@ def get_all_rooms(self) -> list[Room]: ] def get_room(self, room_id: str) -> Room: - """Returns room with the given id""" + """Returns room with the given id. + + Args: + room_id: The ID of the room to retrieve. + + Returns: + Room: The Room object corresponding to the given ID. + """ room = cast( RoomDetailsResponse, self._request(room_get_room, room_id=room_id) @@ -225,17 +285,34 @@ def get_room(self, room_id: str) -> Room: return Room(config=room.config, id=room.id, peers=room.peers) def delete_peer(self, room_id: str, peer_id: str) -> None: - """Deletes peer""" + """Deletes a peer from a room. + + Args: + room_id: The ID of the room the peer belongs to. + peer_id: The ID of the peer to delete. + """ return self._request(room_delete_peer, id=peer_id, room_id=room_id) def delete_room(self, room_id: str) -> None: - """Deletes a room""" + """Deletes a room. + + Args: + room_id: The ID of the room to delete. + """ return self._request(room_delete_room, room_id=room_id) def refresh_peer_token(self, room_id: str, peer_id: str) -> str: - """Refreshes peer token""" + """Refreshes a peer token. + + Args: + room_id: The ID of the room. + peer_id: The ID of the peer whose token needs refreshing. + + Returns: + str: The new peer token. + """ response = cast( PeerRefreshTokenResponse, @@ -245,7 +322,14 @@ def refresh_peer_token(self, room_id: str, peer_id: str) -> str: return response.data.token def create_livestream_viewer_token(self, room_id: str) -> str: - """Generates viewer token for livestream rooms""" + """Generates a viewer token for livestream rooms. + + Args: + room_id: The ID of the livestream room. + + Returns: + str: The generated viewer token. + """ response = cast( ViewerToken, self._request(viewer_generate_viewer_token, room_id=room_id) @@ -254,7 +338,14 @@ def create_livestream_viewer_token(self, room_id: str) -> str: return response.token def create_livestream_streamer_token(self, room_id: str) -> str: - """Generates streamer token for livestream rooms""" + """Generates a streamer token for livestream rooms. + + Args: + room_id: The ID of the livestream room. + + Returns: + str: The generated streamer token. + """ response = cast( StreamerToken, @@ -264,7 +355,13 @@ def create_livestream_streamer_token(self, room_id: str) -> str: return response.token def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str): - """Subscribe a peer to all tracks of another peer.""" + """Subscribes a peer to all tracks of another peer. + + Args: + room_id: The ID of the room. + peer_id: The ID of the subscribing peer. + target_peer_id: The ID of the peer to subscribe to. + """ self._request( room_subscribe_peer, @@ -274,7 +371,13 @@ def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str): ) def subscribe_tracks(self, room_id: str, peer_id: str, track_ids: list[str]): - """Subscribe a peer to specific tracks of another peer.""" + """Subscribes a peer to specific tracks of another peer. + + Args: + room_id: The ID of the room. + peer_id: The ID of the subscribing peer. + track_ids: A list of track IDs to subscribe to. + """ self._request( room_subscribe_tracks, From 4b136822b2a0648abc87c1c2c753531b0b2228d8 Mon Sep 17 00:00:00 2001 From: p1003 Date: Wed, 10 Dec 2025 15:13:44 +0100 Subject: [PATCH 2/7] fix too long lines --- fishjam/api/_fishjam_client.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fishjam/api/_fishjam_client.py b/fishjam/api/_fishjam_client.py index f5104a6..a37baa4 100644 --- a/fishjam/api/_fishjam_client.py +++ b/fishjam/api/_fishjam_client.py @@ -75,7 +75,8 @@ class RoomOptions: max_peers: Maximum amount of peers allowed into the room. video_codec: Enforces video codec for each peer in the room. webhook_url: URL where Fishjam notifications will be sent. - room_type: The use-case of the room. If not provided, this defaults to conference. + room_type: The use-case of the room. If not provided, this defaults + to conference. public: True if livestream viewers can omit specifying a token. """ @@ -200,7 +201,8 @@ def create_agent(self, room_id: str, options: AgentOptions | None = None): options: Configuration options for the agent. Defaults to None. Returns: - Agent: The created agent instance initialized with peer ID, room ID, token, and Fishjam URL. + Agent: The created agent instance initialized with peer ID, room ID, token, + and Fishjam URL. """ options = options or AgentOptions() body = AddPeerBody( From a28b3be1937104a053ce1ab91e3bf5a0d1c10494 Mon Sep 17 00:00:00 2001 From: p1003 Date: Wed, 10 Dec 2025 15:54:24 +0100 Subject: [PATCH 3/7] update ruff --- pyproject.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 35efbd0..ab7efff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,8 +68,11 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.ruff.lint] -select = ["F", "I", "E"] -ignore = [] +select = ["W", "I", "F", "E", "D"] +ignore = ["D107"] + +[tool.ruff.lint.pydocstyle] +convention = "google" [tool.ruff.lint.extend-per-file-ignores] "fishjam/_openapi_client/**" = ["E501"] From a8ee1570592aac1f218751b3ebae25a413076fd8 Mon Sep 17 00:00:00 2001 From: p1003 Date: Wed, 10 Dec 2025 16:23:07 +0100 Subject: [PATCH 4/7] linter --- fishjam/__init__.py | 4 +--- fishjam/_webhook_notifier.py | 10 +++------- fishjam/_ws_notifier.py | 24 ++++++----------------- fishjam/agent/agent.py | 36 ++++++++++++---------------------- fishjam/api/_fishjam_client.py | 13 +----------- fishjam/errors.py | 3 --- fishjam/events/__init__.py | 4 +--- pyproject.toml | 19 ++++++++++++++++-- 8 files changed, 42 insertions(+), 71 deletions(-) diff --git a/fishjam/__init__.py b/fishjam/__init__.py index 02ba691..3778e85 100644 --- a/fishjam/__init__.py +++ b/fishjam/__init__.py @@ -1,6 +1,4 @@ -""" -.. include:: ../README.md -""" +""".. include:: ../README.md""" # pylint: disable=locally-disabled, no-name-in-module, import-error diff --git a/fishjam/_webhook_notifier.py b/fishjam/_webhook_notifier.py index 32c0e72..616e777 100644 --- a/fishjam/_webhook_notifier.py +++ b/fishjam/_webhook_notifier.py @@ -1,8 +1,4 @@ -""" -Module defining a function allowing decoding received webhook -notification from fishjam to notification structs. -""" - +"""Module for decoding received webhook notifications from Fishjam.""" from typing import Union import betterproto @@ -15,8 +11,8 @@ def receive_binary(binary: bytes) -> Union[AllowedNotification, None]: - """ - Transform received protobuf notification to adequate notification instance. + """Transform received protobuf notification to adequate notification instance. + The available notifications are listed in `fishjam.events` module. """ message = ServerMessage().parse(binary) diff --git a/fishjam/_ws_notifier.py b/fishjam/_ws_notifier.py index 7ff5427..453a772 100644 --- a/fishjam/_ws_notifier.py +++ b/fishjam/_ws_notifier.py @@ -1,6 +1,4 @@ -""" -Notifier listening to WebSocket events -""" +"""Notifier listening to WebSocket events""" import asyncio import inspect @@ -32,19 +30,14 @@ class FishjamNotifier: - """ - Allows for receiving WebSocket messages from Fishjam. - """ + """Allows for receiving WebSocket messages from Fishjam.""" def __init__( self, fishjam_id: str, management_token: str, ): - """ - Create FishjamNotifier instance, providing the fishjam id and management token. - """ - + """Create a FishjamNotifier instance with an ID and management token.""" websocket_url = get_fishjam_url(fishjam_id).replace("http", "ws") self._fishjam_url = f"{websocket_url}/socket/server/websocket" self._management_token: str = management_token @@ -56,16 +49,12 @@ def __init__( self._notification_handler: NotificationHandler | None = None def on_server_notification(self, handler: NotificationHandler): - """ - Decorator used for defining handler for Fishjam Notifications - """ + """Decorator used for defining handler for Fishjam Notifications""" self._notification_handler = handler return handler async def connect(self): - """ - A coroutine which connects FishjamNotifier to Fishjam and listens for - all incoming messages from the Fishjam. + """Connects to Fishjam and listens for all incoming messages. It runs until the connection isn't closed. @@ -94,8 +83,7 @@ async def connect(self): self._websocket = None async def wait_ready(self) -> None: - """ - Waits until the notifier is connected and authenticated to Fishjam. + """Waits until the notifier is connected and authenticated to Fishjam. If already connected, returns immediately. """ diff --git a/fishjam/agent/agent.py b/fishjam/agent/agent.py index 80031e1..0a345f0 100644 --- a/fishjam/agent/agent.py +++ b/fishjam/agent/agent.py @@ -58,11 +58,10 @@ class OutgoingAudioTrackOptions: @dataclass(frozen=True) class OutgoingTrack: - """ - Represents an outgoing track of an agent connected to Fishjam, - created by :func:`Agent.add_track`. - """ + """Represents an outgoing track of an agent connected to Fishjam. + This is created by :func:`Agent.add_track`. + """ id: str """The global identifier of the track.""" session: AgentSession @@ -71,8 +70,7 @@ class OutgoingTrack: """The parameters used to create the track.""" async def send_chunk(self, data: bytes): - """ - Send a chunk of audio to Fishjam on this track. + """Send a chunk of audio to Fishjam on this track. Peers connected to the room of the agent will receive this data. """ @@ -86,8 +84,7 @@ async def send_chunk(self, data: bytes): await self.session._send(message) async def interrupt(self): - """ - Interrupt current track. + """Interrupt current track. Any audio that has been sent, but not played will be cleared and be prevented from playing. @@ -111,10 +108,7 @@ def __init__(self, agent: Agent, websocket: ClientConnection): self._closed = False async def receive(self) -> AsyncIterator[IncomingAgentMessage]: - """ - Returns an infinite async iterator over the incoming messages from Fishjam to - the agent. - """ + """Returns an infinite async iterator over incoming messages from Fishjam.""" while message := await self._ws.recv(decode=False): parsed = AgentResponse().parse(message) _, msg = betterproto.which_one_of(parsed, "content") @@ -123,8 +117,7 @@ async def receive(self) -> AsyncIterator[IncomingAgentMessage]: yield content async def add_track(self, options: OutgoingAudioTrackOptions): - """ - Adds a track to the connected agent, with the specified options and metadata. + """Adds a track to the connected agent, with the specified options and metadata. Returns an instance of :class:`OutgoingTrack`, which can be used to send data over the added track. @@ -152,27 +145,25 @@ async def _send(self, message: AgentRequest): await self._ws.send(bytes(message), text=False) async def disconnect(self): - """ - Ends the agent session by closing the websocket connection. + """Ends the agent session by closing the websocket connection. + Useful when you don't use the context manager to obtain the session. """ await self._ws.close() class Agent: - """ - Allows for connecting to a Fishjam room as an agent peer. + """Allows for connecting to a Fishjam room as an agent peer. + Provides callbacks for receiving audio. """ def __init__(self, id: str, room_id: str, token: str, fishjam_url: str): - """ - Create Agent instance, providing the fishjam id and management token. + """Create Agent instance, providing the fishjam id and management token. This constructor should not be called directly. Instead, you should call :func:`fishjam.FishjamClient.create_agent`. """ - self.id = id self.room_id = room_id @@ -181,8 +172,7 @@ def __init__(self, id: str, room_id: str, token: str, fishjam_url: str): @asynccontextmanager async def connect(self): - """ - Connect the agent to Fishjam to start receiving messages. + """Connect the agent to Fishjam to start receiving messages. Incoming messages from Fishjam will be routed to handlers defined with :func:`on_track_data`. diff --git a/fishjam/api/_fishjam_client.py b/fishjam/api/_fishjam_client.py index a37baa4..4b8f8c9 100644 --- a/fishjam/api/_fishjam_client.py +++ b/fishjam/api/_fishjam_client.py @@ -1,6 +1,4 @@ -""" -Fishjam client used to manage rooms -""" +"""Fishjam client used to manage rooms""" from dataclasses import dataclass, field from typing import Any, Literal, cast @@ -263,7 +261,6 @@ def get_all_rooms(self) -> list[Room]: Returns: list[Room]: A list of all available Room objects. """ - rooms = cast(RoomsListingResponse, self._request(room_get_all_rooms)).data return [ @@ -279,7 +276,6 @@ def get_room(self, room_id: str) -> Room: Returns: Room: The Room object corresponding to the given ID. """ - room = cast( RoomDetailsResponse, self._request(room_get_room, room_id=room_id) ).data @@ -293,7 +289,6 @@ def delete_peer(self, room_id: str, peer_id: str) -> None: room_id: The ID of the room the peer belongs to. peer_id: The ID of the peer to delete. """ - return self._request(room_delete_peer, id=peer_id, room_id=room_id) def delete_room(self, room_id: str) -> None: @@ -302,7 +297,6 @@ def delete_room(self, room_id: str) -> None: Args: room_id: The ID of the room to delete. """ - return self._request(room_delete_room, room_id=room_id) def refresh_peer_token(self, room_id: str, peer_id: str) -> str: @@ -315,7 +309,6 @@ def refresh_peer_token(self, room_id: str, peer_id: str) -> str: Returns: str: The new peer token. """ - response = cast( PeerRefreshTokenResponse, self._request(room_refresh_token, id=peer_id, room_id=room_id), @@ -332,7 +325,6 @@ def create_livestream_viewer_token(self, room_id: str) -> str: Returns: str: The generated viewer token. """ - response = cast( ViewerToken, self._request(viewer_generate_viewer_token, room_id=room_id) ) @@ -348,7 +340,6 @@ def create_livestream_streamer_token(self, room_id: str) -> str: Returns: str: The generated streamer token. """ - response = cast( StreamerToken, self._request(streamer_generate_streamer_token, room_id=room_id), @@ -364,7 +355,6 @@ def subscribe_peer(self, room_id: str, peer_id: str, target_peer_id: str): peer_id: The ID of the subscribing peer. target_peer_id: The ID of the peer to subscribe to. """ - self._request( room_subscribe_peer, room_id=room_id, @@ -380,7 +370,6 @@ def subscribe_tracks(self, room_id: str, peer_id: str, track_ids: list[str]): peer_id: The ID of the subscribing peer. track_ids: A list of track IDs to subscribe to. """ - self._request( room_subscribe_tracks, room_id=room_id, diff --git a/fishjam/errors.py b/fishjam/errors.py index c34dd0f..8b4f698 100644 --- a/fishjam/errors.py +++ b/fishjam/errors.py @@ -5,12 +5,9 @@ class HTTPError(Exception): - """""" - @staticmethod def from_response(response: Response[Error]): """@private""" - if not response.parsed: raise RuntimeError("Got endpoint error reponse without parsed field") diff --git a/fishjam/events/__init__.py b/fishjam/events/__init__.py index 738af9a..f5e1feb 100644 --- a/fishjam/events/__init__.py +++ b/fishjam/events/__init__.py @@ -1,6 +1,4 @@ -""" -.. include:: ../../docs/server_notifications.md -""" +""".. include:: ../../docs/server_notifications.md""" # Exported messages from fishjam.events._protos.fishjam import ( diff --git a/pyproject.toml b/pyproject.toml index ab7efff..347fe8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,13 +69,28 @@ build-backend = "hatchling.build" [tool.ruff.lint] select = ["W", "I", "F", "E", "D"] -ignore = ["D107"] +ignore = [ + "D100", + "D101", + "D102", + "D103", + "D104", + "D105", + "D107", + "D415", # """@private""" would not be allowed +] [tool.ruff.lint.pydocstyle] convention = "google" [tool.ruff.lint.extend-per-file-ignores] -"fishjam/_openapi_client/**" = ["E501"] +"fishjam/_openapi_client/**" = ["E501", "D"] +"fishjam/events/_protos/**" = ["D"] +"tests/**" = ["D"] +"scripts.py" = ["D"] +"" = ["D"] + + [tool.pytest.ini_options] markers = [ From c4a213b20560eebe0be4ac73f379211365857aa6 Mon Sep 17 00:00:00 2001 From: p1003 Date: Wed, 10 Dec 2025 16:29:14 +0100 Subject: [PATCH 5/7] ignore D419 for errors.py --- fishjam/agent/agent.py | 1 + fishjam/errors.py | 2 ++ pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fishjam/agent/agent.py b/fishjam/agent/agent.py index 0a345f0..8daf5d6 100644 --- a/fishjam/agent/agent.py +++ b/fishjam/agent/agent.py @@ -62,6 +62,7 @@ class OutgoingTrack: This is created by :func:`Agent.add_track`. """ + id: str """The global identifier of the track.""" session: AgentSession diff --git a/fishjam/errors.py b/fishjam/errors.py index 8b4f698..32d5dee 100644 --- a/fishjam/errors.py +++ b/fishjam/errors.py @@ -5,6 +5,8 @@ class HTTPError(Exception): + """""" + @staticmethod def from_response(response: Response[Error]): """@private""" diff --git a/pyproject.toml b/pyproject.toml index 347fe8f..a421ae1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,9 +86,9 @@ convention = "google" [tool.ruff.lint.extend-per-file-ignores] "fishjam/_openapi_client/**" = ["E501", "D"] "fishjam/events/_protos/**" = ["D"] +"fishjam/errors.py" = ["D419"] "tests/**" = ["D"] "scripts.py" = ["D"] -"" = ["D"] From 15df7a7e81c035f1549e9a9e542339d1ba1f4a35 Mon Sep 17 00:00:00 2001 From: p1003 Date: Wed, 10 Dec 2025 16:42:37 +0100 Subject: [PATCH 6/7] ignore D415 only in errors.py and __init__.py --- fishjam/_ws_notifier.py | 4 ++-- fishjam/agent/errors.py | 4 ++-- fishjam/api/_fishjam_client.py | 2 +- pyproject.toml | 14 +++----------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/fishjam/_ws_notifier.py b/fishjam/_ws_notifier.py index 453a772..4d4c1e0 100644 --- a/fishjam/_ws_notifier.py +++ b/fishjam/_ws_notifier.py @@ -1,4 +1,4 @@ -"""Notifier listening to WebSocket events""" +"""Notifier listening to WebSocket events.""" import asyncio import inspect @@ -49,7 +49,7 @@ def __init__( self._notification_handler: NotificationHandler | None = None def on_server_notification(self, handler: NotificationHandler): - """Decorator used for defining handler for Fishjam Notifications""" + """Decorator used for defining handler for Fishjam Notifications.""" self._notification_handler = handler return handler diff --git a/fishjam/agent/errors.py b/fishjam/agent/errors.py index 89496df..46fa2c4 100644 --- a/fishjam/agent/errors.py +++ b/fishjam/agent/errors.py @@ -1,9 +1,9 @@ class AgentError(Exception): - """Base exception class for all agent exceptions""" + """Base exception class for all agent exceptions.""" class AgentAuthError(AgentError): - """Agent failed to authenticate properly""" + """Agent failed to authenticate properly.""" def __init__(self, reason: str): self.reason = reason diff --git a/fishjam/api/_fishjam_client.py b/fishjam/api/_fishjam_client.py index 4b8f8c9..1dc44f2 100644 --- a/fishjam/api/_fishjam_client.py +++ b/fishjam/api/_fishjam_client.py @@ -1,4 +1,4 @@ -"""Fishjam client used to manage rooms""" +"""Fishjam client used to manage rooms.""" from dataclasses import dataclass, field from typing import Any, Literal, cast diff --git a/pyproject.toml b/pyproject.toml index a421ae1..04b4f81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,16 +69,7 @@ build-backend = "hatchling.build" [tool.ruff.lint] select = ["W", "I", "F", "E", "D"] -ignore = [ - "D100", - "D101", - "D102", - "D103", - "D104", - "D105", - "D107", - "D415", # """@private""" would not be allowed -] +ignore = ["D100", "D101", "D102", "D103", "D104", "D105", "D107"] [tool.ruff.lint.pydocstyle] convention = "google" @@ -86,7 +77,8 @@ convention = "google" [tool.ruff.lint.extend-per-file-ignores] "fishjam/_openapi_client/**" = ["E501", "D"] "fishjam/events/_protos/**" = ["D"] -"fishjam/errors.py" = ["D419"] +"fishjam/errors.py" = ["D415", "D419"] +"**/__init__.py" = ["D415"] "tests/**" = ["D"] "scripts.py" = ["D"] From e588a34a551d6515dda7f592ee62ac4bf7bd8e95 Mon Sep 17 00:00:00 2001 From: p1003 Date: Thu, 11 Dec 2025 12:39:14 +0100 Subject: [PATCH 7/7] bump ruff to 0.12 and add DOC rule --- .../selective_subscription/app.py | 14 ++- fishjam/_openapi_client/__init__.py | 3 +- fishjam/_openapi_client/api/__init__.py | 2 +- fishjam/_openapi_client/api/room/__init__.py | 2 +- .../_openapi_client/api/stream/__init__.py | 2 +- .../_openapi_client/api/streamer/__init__.py | 2 +- .../_openapi_client/api/viewer/__init__.py | 2 +- fishjam/_openapi_client/errors.py | 2 +- fishjam/_openapi_client/models/__init__.py | 2 +- .../_openapi_client/models/add_peer_body.py | 10 +- fishjam/_openapi_client/models/error.py | 8 +- fishjam/_openapi_client/models/peer.py | 20 ++-- .../models/peer_details_response.py | 8 +- .../models/peer_details_response_data.py | 10 +- .../models/peer_options_agent.py | 6 +- .../models/peer_options_agent_output.py | 12 +-- .../models/peer_options_web_rtc.py | 6 +- .../models/peer_refresh_token_response.py | 8 +- .../peer_refresh_token_response_data.py | 8 +- fishjam/_openapi_client/models/room.py | 12 +-- .../models/room_create_details_response.py | 8 +- .../room_create_details_response_data.py | 10 +- .../models/room_details_response.py | 8 +- .../models/rooms_listing_response.py | 8 +- fishjam/_openapi_client/models/stream.py | 16 ++- fishjam/_openapi_client/models/streamer.py | 12 +-- .../_openapi_client/models/streamer_token.py | 8 +- .../models/streams_listing_response.py | 8 +- .../models/subscribe_tracks_body.py | 8 +- .../_openapi_client/models/subscriptions.py | 10 +- fishjam/_openapi_client/models/viewer.py | 12 +-- .../_openapi_client/models/viewer_token.py | 8 +- fishjam/_openapi_client/types.py | 2 +- fishjam/_webhook_notifier.py | 10 +- fishjam/_ws_notifier.py | 9 +- fishjam/agent/agent.py | 97 +++++++++++-------- pyproject.toml | 18 ++-- uv.lock | 43 ++++---- 38 files changed, 217 insertions(+), 217 deletions(-) diff --git a/examples/selective_subscription/selective_subscription/app.py b/examples/selective_subscription/selective_subscription/app.py index 24e8127..1ddb6bb 100644 --- a/examples/selective_subscription/selective_subscription/app.py +++ b/examples/selective_subscription/selective_subscription/app.py @@ -29,14 +29,12 @@ async def create_peer(request: Request) -> Response: peer, token = room_service.create_peer() - return JSONResponse( - { - "peer_id": peer.id, - "token": token, - "room_name": room_name, - "peer_name": peer_name, - } - ) + return JSONResponse({ + "peer_id": peer.id, + "token": token, + "room_name": room_name, + "peer_name": peer_name, + }) except Exception as e: return JSONResponse({"error": str(e)}, status_code=500) diff --git a/fishjam/_openapi_client/__init__.py b/fishjam/_openapi_client/__init__.py index a38f42d..caae9b2 100644 --- a/fishjam/_openapi_client/__init__.py +++ b/fishjam/_openapi_client/__init__.py @@ -1,4 +1,5 @@ -""" A client library for accessing Fishjam Media Server """ +"""A client library for accessing Fishjam Media Server""" + from .client import AuthenticatedClient, Client __all__ = ( diff --git a/fishjam/_openapi_client/api/__init__.py b/fishjam/_openapi_client/api/__init__.py index dc035f4..81f9fa2 100644 --- a/fishjam/_openapi_client/api/__init__.py +++ b/fishjam/_openapi_client/api/__init__.py @@ -1 +1 @@ -""" Contains methods for accessing the API """ +"""Contains methods for accessing the API""" diff --git a/fishjam/_openapi_client/api/room/__init__.py b/fishjam/_openapi_client/api/room/__init__.py index c9921b5..2d7c0b2 100644 --- a/fishjam/_openapi_client/api/room/__init__.py +++ b/fishjam/_openapi_client/api/room/__init__.py @@ -1 +1 @@ -""" Contains endpoint functions for accessing the API """ +"""Contains endpoint functions for accessing the API""" diff --git a/fishjam/_openapi_client/api/stream/__init__.py b/fishjam/_openapi_client/api/stream/__init__.py index c9921b5..2d7c0b2 100644 --- a/fishjam/_openapi_client/api/stream/__init__.py +++ b/fishjam/_openapi_client/api/stream/__init__.py @@ -1 +1 @@ -""" Contains endpoint functions for accessing the API """ +"""Contains endpoint functions for accessing the API""" diff --git a/fishjam/_openapi_client/api/streamer/__init__.py b/fishjam/_openapi_client/api/streamer/__init__.py index c9921b5..2d7c0b2 100644 --- a/fishjam/_openapi_client/api/streamer/__init__.py +++ b/fishjam/_openapi_client/api/streamer/__init__.py @@ -1 +1 @@ -""" Contains endpoint functions for accessing the API """ +"""Contains endpoint functions for accessing the API""" diff --git a/fishjam/_openapi_client/api/viewer/__init__.py b/fishjam/_openapi_client/api/viewer/__init__.py index c9921b5..2d7c0b2 100644 --- a/fishjam/_openapi_client/api/viewer/__init__.py +++ b/fishjam/_openapi_client/api/viewer/__init__.py @@ -1 +1 @@ -""" Contains endpoint functions for accessing the API """ +"""Contains endpoint functions for accessing the API""" diff --git a/fishjam/_openapi_client/errors.py b/fishjam/_openapi_client/errors.py index 8a10249..5f92e76 100644 --- a/fishjam/_openapi_client/errors.py +++ b/fishjam/_openapi_client/errors.py @@ -1,4 +1,4 @@ -""" Contains shared errors types that can be raised from API functions """ +"""Contains shared errors types that can be raised from API functions""" class UnexpectedStatus(Exception): diff --git a/fishjam/_openapi_client/models/__init__.py b/fishjam/_openapi_client/models/__init__.py index 3f611d3..3d2421e 100644 --- a/fishjam/_openapi_client/models/__init__.py +++ b/fishjam/_openapi_client/models/__init__.py @@ -1,4 +1,4 @@ -""" Contains all the data models used in inputs/outputs """ +"""Contains all the data models used in inputs/outputs""" from .add_peer_body import AddPeerBody from .error import Error diff --git a/fishjam/_openapi_client/models/add_peer_body.py b/fishjam/_openapi_client/models/add_peer_body.py index f96ea33..9134e63 100644 --- a/fishjam/_openapi_client/models/add_peer_body.py +++ b/fishjam/_openapi_client/models/add_peer_body.py @@ -44,12 +44,10 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "options": options, - "type": type_, - } - ) + field_dict.update({ + "options": options, + "type": type_, + }) return field_dict diff --git a/fishjam/_openapi_client/models/error.py b/fishjam/_openapi_client/models/error.py index 14afb29..0087ccf 100644 --- a/fishjam/_openapi_client/models/error.py +++ b/fishjam/_openapi_client/models/error.py @@ -23,11 +23,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "errors": errors, - } - ) + field_dict.update({ + "errors": errors, + }) return field_dict diff --git a/fishjam/_openapi_client/models/peer.py b/fishjam/_openapi_client/models/peer.py index 291a47e..929e519 100644 --- a/fishjam/_openapi_client/models/peer.py +++ b/fishjam/_openapi_client/models/peer.py @@ -72,17 +72,15 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "id": id, - "metadata": metadata, - "status": status, - "subscribeMode": subscribe_mode, - "subscriptions": subscriptions, - "tracks": tracks, - "type": type_, - } - ) + field_dict.update({ + "id": id, + "metadata": metadata, + "status": status, + "subscribeMode": subscribe_mode, + "subscriptions": subscriptions, + "tracks": tracks, + "type": type_, + }) return field_dict diff --git a/fishjam/_openapi_client/models/peer_details_response.py b/fishjam/_openapi_client/models/peer_details_response.py index 6547f61..718c26c 100644 --- a/fishjam/_openapi_client/models/peer_details_response.py +++ b/fishjam/_openapi_client/models/peer_details_response.py @@ -31,11 +31,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "data": data, - } - ) + field_dict.update({ + "data": data, + }) return field_dict diff --git a/fishjam/_openapi_client/models/peer_details_response_data.py b/fishjam/_openapi_client/models/peer_details_response_data.py index f7295bf..fbf3fb3 100644 --- a/fishjam/_openapi_client/models/peer_details_response_data.py +++ b/fishjam/_openapi_client/models/peer_details_response_data.py @@ -42,12 +42,10 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "peer": peer, - "token": token, - } - ) + field_dict.update({ + "peer": peer, + "token": token, + }) if peer_websocket_url is not UNSET: field_dict["peer_websocket_url"] = peer_websocket_url diff --git a/fishjam/_openapi_client/models/peer_options_agent.py b/fishjam/_openapi_client/models/peer_options_agent.py index 0656184..dd02dc8 100644 --- a/fishjam/_openapi_client/models/peer_options_agent.py +++ b/fishjam/_openapi_client/models/peer_options_agent.py @@ -30,9 +30,9 @@ class PeerOptionsAgent: """ output: Union[Unset, "PeerOptionsAgentOutput"] = UNSET - subscribe_mode: Union[ - Unset, PeerOptionsAgentSubscribeMode - ] = PeerOptionsAgentSubscribeMode.AUTO + subscribe_mode: Union[Unset, PeerOptionsAgentSubscribeMode] = ( + PeerOptionsAgentSubscribeMode.AUTO + ) additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: diff --git a/fishjam/_openapi_client/models/peer_options_agent_output.py b/fishjam/_openapi_client/models/peer_options_agent_output.py index 25ae3dc..1d4faf1 100644 --- a/fishjam/_openapi_client/models/peer_options_agent_output.py +++ b/fishjam/_openapi_client/models/peer_options_agent_output.py @@ -30,12 +30,12 @@ class PeerOptionsAgentOutput: Default: PeerOptionsAgentOutputAudioSampleRate.VALUE_16000. Example: 16000. """ - audio_format: Union[ - Unset, PeerOptionsAgentOutputAudioFormat - ] = PeerOptionsAgentOutputAudioFormat.PCM16 - audio_sample_rate: Union[ - Unset, PeerOptionsAgentOutputAudioSampleRate - ] = PeerOptionsAgentOutputAudioSampleRate.VALUE_16000 + audio_format: Union[Unset, PeerOptionsAgentOutputAudioFormat] = ( + PeerOptionsAgentOutputAudioFormat.PCM16 + ) + audio_sample_rate: Union[Unset, PeerOptionsAgentOutputAudioSampleRate] = ( + PeerOptionsAgentOutputAudioSampleRate.VALUE_16000 + ) additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: diff --git a/fishjam/_openapi_client/models/peer_options_web_rtc.py b/fishjam/_openapi_client/models/peer_options_web_rtc.py index 17aca64..617602f 100644 --- a/fishjam/_openapi_client/models/peer_options_web_rtc.py +++ b/fishjam/_openapi_client/models/peer_options_web_rtc.py @@ -32,9 +32,9 @@ class PeerOptionsWebRTC: enable_simulcast: Union[Unset, bool] = True metadata: Union[Unset, "PeerOptionsWebRTCMetadata"] = UNSET - subscribe_mode: Union[ - Unset, PeerOptionsWebRTCSubscribeMode - ] = PeerOptionsWebRTCSubscribeMode.AUTO + subscribe_mode: Union[Unset, PeerOptionsWebRTCSubscribeMode] = ( + PeerOptionsWebRTCSubscribeMode.AUTO + ) additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: diff --git a/fishjam/_openapi_client/models/peer_refresh_token_response.py b/fishjam/_openapi_client/models/peer_refresh_token_response.py index 1100c62..6075525 100644 --- a/fishjam/_openapi_client/models/peer_refresh_token_response.py +++ b/fishjam/_openapi_client/models/peer_refresh_token_response.py @@ -31,11 +31,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "data": data, - } - ) + field_dict.update({ + "data": data, + }) return field_dict diff --git a/fishjam/_openapi_client/models/peer_refresh_token_response_data.py b/fishjam/_openapi_client/models/peer_refresh_token_response_data.py index ccc92ac..ca1aebc 100644 --- a/fishjam/_openapi_client/models/peer_refresh_token_response_data.py +++ b/fishjam/_openapi_client/models/peer_refresh_token_response_data.py @@ -22,11 +22,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "token": token, - } - ) + field_dict.update({ + "token": token, + }) return field_dict diff --git a/fishjam/_openapi_client/models/room.py b/fishjam/_openapi_client/models/room.py index c6e9847..e2c8fbf 100644 --- a/fishjam/_openapi_client/models/room.py +++ b/fishjam/_openapi_client/models/room.py @@ -43,13 +43,11 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "config": config, - "id": id, - "peers": peers, - } - ) + field_dict.update({ + "config": config, + "id": id, + "peers": peers, + }) return field_dict diff --git a/fishjam/_openapi_client/models/room_create_details_response.py b/fishjam/_openapi_client/models/room_create_details_response.py index 23e37e7..89c01f5 100644 --- a/fishjam/_openapi_client/models/room_create_details_response.py +++ b/fishjam/_openapi_client/models/room_create_details_response.py @@ -31,11 +31,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "data": data, - } - ) + field_dict.update({ + "data": data, + }) return field_dict diff --git a/fishjam/_openapi_client/models/room_create_details_response_data.py b/fishjam/_openapi_client/models/room_create_details_response_data.py index 519dd4b..8ac7dc9 100644 --- a/fishjam/_openapi_client/models/room_create_details_response_data.py +++ b/fishjam/_openapi_client/models/room_create_details_response_data.py @@ -35,12 +35,10 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "fishjam_address": fishjam_address, - "room": room, - } - ) + field_dict.update({ + "fishjam_address": fishjam_address, + "room": room, + }) return field_dict diff --git a/fishjam/_openapi_client/models/room_details_response.py b/fishjam/_openapi_client/models/room_details_response.py index 1d184c0..e1b23ef 100644 --- a/fishjam/_openapi_client/models/room_details_response.py +++ b/fishjam/_openapi_client/models/room_details_response.py @@ -31,11 +31,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "data": data, - } - ) + field_dict.update({ + "data": data, + }) return field_dict diff --git a/fishjam/_openapi_client/models/rooms_listing_response.py b/fishjam/_openapi_client/models/rooms_listing_response.py index 9663502..89d647b 100644 --- a/fishjam/_openapi_client/models/rooms_listing_response.py +++ b/fishjam/_openapi_client/models/rooms_listing_response.py @@ -34,11 +34,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "data": data, - } - ) + field_dict.update({ + "data": data, + }) return field_dict diff --git a/fishjam/_openapi_client/models/stream.py b/fishjam/_openapi_client/models/stream.py index a87aa90..0704770 100644 --- a/fishjam/_openapi_client/models/stream.py +++ b/fishjam/_openapi_client/models/stream.py @@ -61,15 +61,13 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "connectedViewers": connected_viewers, - "id": id, - "public": public, - "streamers": streamers, - "viewers": viewers, - } - ) + field_dict.update({ + "connectedViewers": connected_viewers, + "id": id, + "public": public, + "streamers": streamers, + "viewers": viewers, + }) if audio_only is not UNSET: field_dict["audioOnly"] = audio_only diff --git a/fishjam/_openapi_client/models/streamer.py b/fishjam/_openapi_client/models/streamer.py index bc8b8f7..f234c00 100644 --- a/fishjam/_openapi_client/models/streamer.py +++ b/fishjam/_openapi_client/models/streamer.py @@ -41,13 +41,11 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "id": id, - "status": status, - "token": token, - } - ) + field_dict.update({ + "id": id, + "status": status, + "token": token, + }) return field_dict diff --git a/fishjam/_openapi_client/models/streamer_token.py b/fishjam/_openapi_client/models/streamer_token.py index 4db3f8a..e675c0d 100644 --- a/fishjam/_openapi_client/models/streamer_token.py +++ b/fishjam/_openapi_client/models/streamer_token.py @@ -23,11 +23,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "token": token, - } - ) + field_dict.update({ + "token": token, + }) return field_dict diff --git a/fishjam/_openapi_client/models/streams_listing_response.py b/fishjam/_openapi_client/models/streams_listing_response.py index 86c9fef..d451de5 100644 --- a/fishjam/_openapi_client/models/streams_listing_response.py +++ b/fishjam/_openapi_client/models/streams_listing_response.py @@ -34,11 +34,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "data": data, - } - ) + field_dict.update({ + "data": data, + }) return field_dict diff --git a/fishjam/_openapi_client/models/subscribe_tracks_body.py b/fishjam/_openapi_client/models/subscribe_tracks_body.py index 1ce94a7..8daacc1 100644 --- a/fishjam/_openapi_client/models/subscribe_tracks_body.py +++ b/fishjam/_openapi_client/models/subscribe_tracks_body.py @@ -26,11 +26,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "track_ids": track_ids, - } - ) + field_dict.update({ + "track_ids": track_ids, + }) return field_dict diff --git a/fishjam/_openapi_client/models/subscriptions.py b/fishjam/_openapi_client/models/subscriptions.py index 673e2e1..82f61d3 100644 --- a/fishjam/_openapi_client/models/subscriptions.py +++ b/fishjam/_openapi_client/models/subscriptions.py @@ -31,12 +31,10 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "peers": peers, - "tracks": tracks, - } - ) + field_dict.update({ + "peers": peers, + "tracks": tracks, + }) return field_dict diff --git a/fishjam/_openapi_client/models/viewer.py b/fishjam/_openapi_client/models/viewer.py index 66b8c61..b34aeaa 100644 --- a/fishjam/_openapi_client/models/viewer.py +++ b/fishjam/_openapi_client/models/viewer.py @@ -41,13 +41,11 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "id": id, - "status": status, - "token": token, - } - ) + field_dict.update({ + "id": id, + "status": status, + "token": token, + }) return field_dict diff --git a/fishjam/_openapi_client/models/viewer_token.py b/fishjam/_openapi_client/models/viewer_token.py index 3a2e861..dee5c4a 100644 --- a/fishjam/_openapi_client/models/viewer_token.py +++ b/fishjam/_openapi_client/models/viewer_token.py @@ -23,11 +23,9 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "token": token, - } - ) + field_dict.update({ + "token": token, + }) return field_dict diff --git a/fishjam/_openapi_client/types.py b/fishjam/_openapi_client/types.py index 127da11..1b96ca4 100644 --- a/fishjam/_openapi_client/types.py +++ b/fishjam/_openapi_client/types.py @@ -1,4 +1,4 @@ -""" Contains some shared types for properties """ +"""Contains some shared types for properties""" from collections.abc import Mapping, MutableMapping from http import HTTPStatus diff --git a/fishjam/_webhook_notifier.py b/fishjam/_webhook_notifier.py index 616e777..beb9693 100644 --- a/fishjam/_webhook_notifier.py +++ b/fishjam/_webhook_notifier.py @@ -1,4 +1,5 @@ """Module for decoding received webhook notifications from Fishjam.""" + from typing import Union import betterproto @@ -11,9 +12,16 @@ def receive_binary(binary: bytes) -> Union[AllowedNotification, None]: - """Transform received protobuf notification to adequate notification instance. + """Transforms a received protobuf notification into a notification instance. The available notifications are listed in `fishjam.events` module. + + Args: + binary: The raw binary data received from the webhook. + + Returns: + AllowedNotification | None: The parsed notification object, or None if + the message type is not supported. """ message = ServerMessage().parse(binary) _which, message = betterproto.which_one_of(message, "content") diff --git a/fishjam/_ws_notifier.py b/fishjam/_ws_notifier.py index 4d4c1e0..b3c2696 100644 --- a/fishjam/_ws_notifier.py +++ b/fishjam/_ws_notifier.py @@ -49,7 +49,14 @@ def __init__( self._notification_handler: NotificationHandler | None = None def on_server_notification(self, handler: NotificationHandler): - """Decorator used for defining handler for Fishjam Notifications.""" + """Decorator for defining a handler for Fishjam notifications. + + Args: + handler: The function to be registered as the notification handler. + + Returns: + NotificationHandler: The original handler function (unmodified). + """ self._notification_handler = handler return handler diff --git a/fishjam/agent/agent.py b/fishjam/agent/agent.py index 8daf5d6..56ce707 100644 --- a/fishjam/agent/agent.py +++ b/fishjam/agent/agent.py @@ -28,32 +28,20 @@ @dataclass class OutgoingAudioTrackOptions: - """Parameters of an outgoing audio track.""" - - encoding: TrackEncoding = TrackEncoding.TRACK_ENCODING_UNSPECIFIED - """ - The encoding of the audio source. - Defaults to raw 16-bit PCM. + """Parameters of an outgoing audio track. + + Attributes: + encoding: The encoding of the audio source. Defaults to raw 16-bit PCM. + sample_rate: The sample rate of the audio source. Defaults to 16000. + channels: The number of channels in the audio source. Supported values are + 1 (mono) and 2 (stereo). Defaults to 1 (mono). + metadata: Custom metadata for the track. Must be JSON-encodable. """ + encoding: TrackEncoding = TrackEncoding.TRACK_ENCODING_UNSPECIFIED sample_rate: Literal[16000, 24000] = 16000 - """ - The sample rate of the audio source. - Defaults to 16000. - """ - channels: Literal[1, 2] = 1 - """ - The number of channels in the audio source. - Supported values are 1 (mono) and 2 (stereo). - Defaults to 1 (mono) - """ - metadata: dict[str, Any] | None = None - """ - Custom metadata for the track. - Must be JSON-encodable. - """ @dataclass(frozen=True) @@ -61,19 +49,24 @@ class OutgoingTrack: """Represents an outgoing track of an agent connected to Fishjam. This is created by :func:`Agent.add_track`. + + Attributes: + id: The global identifier of the track. + session: The agent the track belongs to. + options: The parameters used to create the track. """ id: str - """The global identifier of the track.""" session: AgentSession - """The agent the track belongs to.""" options: OutgoingAudioTrackOptions - """The parameters used to create the track.""" async def send_chunk(self, data: bytes): - """Send a chunk of audio to Fishjam on this track. + """Sends a chunk of audio to Fishjam on this track. Peers connected to the room of the agent will receive this data. + + Args: + data: The raw audio bytes to send. """ message = AgentRequest( track_data=OutgoingTrackData( @@ -85,12 +78,11 @@ async def send_chunk(self, data: bytes): await self.session._send(message) async def interrupt(self): - """Interrupt current track. - - Any audio that has been sent, but not played - will be cleared and be prevented from playing. + """Interrupts the current track. - Audio sent after the interrupt will be played normally. + Any audio that has been sent, but not played, will be cleared and + prevented from playing. Audio sent after the interrupt will be played + normally. """ message = AgentRequest( interrupt_track=AgentRequestInterruptTrack( @@ -102,14 +94,26 @@ async def interrupt(self): class AgentSession: + """Represents an active connection session for an Agent.""" + def __init__(self, agent: Agent, websocket: ClientConnection): + """Initializes the AgentSession. + + Args: + agent: The Agent instance owning this session. + websocket: The active websocket connection. + """ self.agent = agent self._ws = websocket self._closed = False async def receive(self) -> AsyncIterator[IncomingAgentMessage]: - """Returns an infinite async iterator over incoming messages from Fishjam.""" + """Returns an async iterator over incoming messages from Fishjam. + + Yields: + IncomingAgentMessage: The next message received from the server. + """ while message := await self._ws.recv(decode=False): parsed = AgentResponse().parse(message) _, msg = betterproto.which_one_of(parsed, "content") @@ -117,11 +121,14 @@ async def receive(self) -> AsyncIterator[IncomingAgentMessage]: case IncomingTrackData() as content: yield content - async def add_track(self, options: OutgoingAudioTrackOptions): - """Adds a track to the connected agent, with the specified options and metadata. + async def add_track(self, options: OutgoingAudioTrackOptions) -> OutgoingTrack: + """Adds a track to the connected agent with the specified options. + + Args: + options: Configuration options and metadata for the new track. - Returns an instance of :class:`OutgoingTrack`, which can be used to send data - over the added track. + Returns: + OutgoingTrack: An object used to send data over the added track. """ track_id = uuid.uuid4().hex metadata_json = json.dumps(options.metadata) @@ -157,13 +164,23 @@ class Agent: """Allows for connecting to a Fishjam room as an agent peer. Provides callbacks for receiving audio. + + Attributes: + id: The unique identifier of the agent. + room_id: The ID of the room the agent is connecting to. """ def __init__(self, id: str, room_id: str, token: str, fishjam_url: str): - """Create Agent instance, providing the fishjam id and management token. + """Creates an Agent instance. This constructor should not be called directly. Instead, you should call :func:`fishjam.FishjamClient.create_agent`. + + Args: + id: The unique identifier for the agent. + room_id: The ID of the room the agent will join. + token: The authentication token for the agent. + fishjam_url: The URL of the Fishjam instance. """ self.id = id self.room_id = room_id @@ -173,12 +190,16 @@ def __init__(self, id: str, room_id: str, token: str, fishjam_url: str): @asynccontextmanager async def connect(self): - """Connect the agent to Fishjam to start receiving messages. + """Connects the agent to Fishjam to start receiving messages. Incoming messages from Fishjam will be routed to handlers defined with :func:`on_track_data`. - :raises AgentAuthError: authentication failed + Yields: + AgentSession: An active session for sending media and handling events. + + Raises: + AgentAuthError: If authentication with the Fishjam server fails. """ async with client.connect(self._socket_url) as websocket: await self._authenticate(websocket) diff --git a/pyproject.toml b/pyproject.toml index 04b4f81..aa8c356 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ dev = [ "mkdocs>=1.5.3,<2", "mike>=2.0.0,<3", "openapi-python-client>=0.25.0,<0.26", - "ruff>=0.2,<0.3", + "ruff==0.12", "flask>=3.0.3,<4", "pyright>=1.1.383,<2", ] @@ -67,23 +67,27 @@ include = ["fishjam"] requires = ["hatchling"] build-backend = "hatchling.build" +[tool.ruff] +preview = true + [tool.ruff.lint] -select = ["W", "I", "F", "E", "D"] -ignore = ["D100", "D101", "D102", "D103", "D104", "D105", "D107"] +select = ["W", "I", "F", "E", "D", "DOC"] +ignore = ["D100", "D101", "D102", "D103", "D104", "D105", "D107", "DOC502"] [tool.ruff.lint.pydocstyle] convention = "google" [tool.ruff.lint.extend-per-file-ignores] -"fishjam/_openapi_client/**" = ["E501", "D"] -"fishjam/events/_protos/**" = ["D"] -"fishjam/errors.py" = ["D415", "D419"] -"**/__init__.py" = ["D415"] +"fishjam/_openapi_client/**" = ["E501", "D", "DOC"] +"fishjam/events/_protos/**" = ["D", "DOC"] +"fishjam/errors.py" = ["D415", "D419", "DOC501", "DOC201"] +"**/__init__.py" = ["D415", "DOC"] "tests/**" = ["D"] "scripts.py" = ["D"] + [tool.pytest.ini_options] markers = [ "file_component_sources: Tests requiring files uploaded for File Component", diff --git a/uv.lock b/uv.lock index affdf4a..377ea3f 100644 --- a/uv.lock +++ b/uv.lock @@ -347,7 +347,7 @@ dev = [ { name = "openapi-python-client", specifier = ">=0.25.0,<0.26" }, { name = "pdoc", specifier = ">=15.0.0,<16" }, { name = "pyright", specifier = ">=1.1.383,<2" }, - { name = "ruff", specifier = ">=0.2,<0.3" }, + { name = "ruff", specifier = "==0.12" }, ] test = [ { name = "flask", specifier = ">=3.0.3,<4" }, @@ -1899,26 +1899,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/06/b2e9ee5f17dab59476fcb6cc6fdd268e8340d95b7dfc760ed93f4243f16f/ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d", size = 2040633, upload-time = "2024-02-17T22:36:38.19Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/21/e56126ca3b56e6d05a0f6744558305f6589327945ee01b85ffe85a0f37bf/ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6", size = 14894866, upload-time = "2024-02-17T22:35:45.715Z" }, - { url = "https://files.pythonhosted.org/packages/b6/1e/fd238f116e2fab69a2fbb4c3ab8903225836cb6d900ff8139c03c2f6f7b7/ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39", size = 7634941, upload-time = "2024-02-17T22:35:51.518Z" }, - { url = "https://files.pythonhosted.org/packages/4c/53/30651b54241f4f26796cbc5b7cdcafebf5ecd7a30997e7a08673e8050b30/ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73", size = 7332185, upload-time = "2024-02-17T22:35:55.053Z" }, - { url = "https://files.pythonhosted.org/packages/1c/8a/8c14e40da4cb8d651fc78f769e938552069e7bc34e9e65f7335f3469f9d2/ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba", size = 6739587, upload-time = "2024-02-17T22:35:57.465Z" }, - { url = "https://files.pythonhosted.org/packages/db/71/5be31e5505307e852020d624049ae6610e1ebb68431bb03251904aa082c6/ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c", size = 7813597, upload-time = "2024-02-17T22:36:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/45/20/89df4f35f0644b529b9e8bb4c9a0a4633ad2fcba888941caaba744ae5768/ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e", size = 8465022, upload-time = "2024-02-17T22:36:03.46Z" }, - { url = "https://files.pythonhosted.org/packages/ec/c2/d2f2b750971593580b29d965bd7bc36a7f5e971b3de24e342235ae7578a9/ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca", size = 8196736, upload-time = "2024-02-17T22:36:07.188Z" }, - { url = "https://files.pythonhosted.org/packages/bc/83/0dfcc589d8d4d27c551dfb5d50ef57b58fc6432298bc115010f7a0642f48/ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001", size = 8896228, upload-time = "2024-02-17T22:36:10.642Z" }, - { url = "https://files.pythonhosted.org/packages/27/f1/3bf230a048561fd03bc779f2a3e5b05d8ea8cb1c91456a4246c5673b8ef5/ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3", size = 7817875, upload-time = "2024-02-17T22:36:15.006Z" }, - { url = "https://files.pythonhosted.org/packages/63/ad/57e10d775d94a22eabdbe272d6ebb687d10ff0312ad8cd81dbc3bdf74081/ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726", size = 7248228, upload-time = "2024-02-17T22:36:17.976Z" }, - { url = "https://files.pythonhosted.org/packages/1d/65/250a8dd655563a31d7f38af35e5a2860a54bc66c121084f36c63d46dd687/ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e", size = 6735053, upload-time = "2024-02-17T22:36:20.94Z" }, - { url = "https://files.pythonhosted.org/packages/ac/e5/6684718861b205985164afb9a1a8ab83deb4fa2326c903570e9d1af9347a/ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e", size = 7471896, upload-time = "2024-02-17T22:36:23.793Z" }, - { url = "https://files.pythonhosted.org/packages/4c/40/25de7bd89d5af3cd033d42935c7ea2bc79f52fa2f2cf4cbd8f1dbc2cae2b/ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9", size = 7883633, upload-time = "2024-02-17T22:36:26.637Z" }, - { url = "https://files.pythonhosted.org/packages/49/98/9c678bd07561bcdf2129df8284b5708e0393e7c52256db9b30b1b1043cfd/ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325", size = 6909240, upload-time = "2024-02-17T22:36:29.721Z" }, - { url = "https://files.pythonhosted.org/packages/47/d2/23fe9d73dadec045cbffc0c2046a34f7b829f217abd76fb2d6ef7114d792/ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d", size = 7593466, upload-time = "2024-02-17T22:36:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/1a/83/0d002e72ba3c15a74e5ac63d31f57d222d8f297e637d065db28f1253f109/ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd", size = 7222811, upload-time = "2024-02-17T22:36:35.499Z" }, +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/90/5255432602c0b196a0da6720f6f76b93eb50baef46d3c9b0025e2f9acbf3/ruff-0.12.0.tar.gz", hash = "sha256:4d047db3662418d4a848a3fdbfaf17488b34b62f527ed6f10cb8afd78135bc5c", size = 4376101, upload-time = "2025-06-17T15:19:26.217Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/fd/b46bb20e14b11ff49dbc74c61de352e0dc07fb650189513631f6fb5fc69f/ruff-0.12.0-py3-none-linux_armv6l.whl", hash = "sha256:5652a9ecdb308a1754d96a68827755f28d5dfb416b06f60fd9e13f26191a8848", size = 10311554, upload-time = "2025-06-17T15:18:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/e7/d3/021dde5a988fa3e25d2468d1dadeea0ae89dc4bc67d0140c6e68818a12a1/ruff-0.12.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:05ed0c914fabc602fc1f3b42c53aa219e5736cb030cdd85640c32dbc73da74a6", size = 11118435, upload-time = "2025-06-17T15:18:49.064Z" }, + { url = "https://files.pythonhosted.org/packages/07/a2/01a5acf495265c667686ec418f19fd5c32bcc326d4c79ac28824aecd6a32/ruff-0.12.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:07a7aa9b69ac3fcfda3c507916d5d1bca10821fe3797d46bad10f2c6de1edda0", size = 10466010, upload-time = "2025-06-17T15:18:51.341Z" }, + { url = "https://files.pythonhosted.org/packages/4c/57/7caf31dd947d72e7aa06c60ecb19c135cad871a0a8a251723088132ce801/ruff-0.12.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7731c3eec50af71597243bace7ec6104616ca56dda2b99c89935fe926bdcd48", size = 10661366, upload-time = "2025-06-17T15:18:53.29Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ba/aa393b972a782b4bc9ea121e0e358a18981980856190d7d2b6187f63e03a/ruff-0.12.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:952d0630eae628250ab1c70a7fffb641b03e6b4a2d3f3ec6c1d19b4ab6c6c807", size = 10173492, upload-time = "2025-06-17T15:18:55.262Z" }, + { url = "https://files.pythonhosted.org/packages/d7/50/9349ee777614bc3062fc6b038503a59b2034d09dd259daf8192f56c06720/ruff-0.12.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c021f04ea06966b02614d442e94071781c424ab8e02ec7af2f037b4c1e01cc82", size = 11761739, upload-time = "2025-06-17T15:18:58.906Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/ad459de67c70ec112e2ba7206841c8f4eb340a03ee6a5cabc159fe558b8e/ruff-0.12.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d235618283718ee2fe14db07f954f9b2423700919dc688eacf3f8797a11315c", size = 12537098, upload-time = "2025-06-17T15:19:01.316Z" }, + { url = "https://files.pythonhosted.org/packages/ed/50/15ad9c80ebd3c4819f5bd8883e57329f538704ed57bac680d95cb6627527/ruff-0.12.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0758038f81beec8cc52ca22de9685b8ae7f7cc18c013ec2050012862cc9165", size = 12154122, upload-time = "2025-06-17T15:19:03.727Z" }, + { url = "https://files.pythonhosted.org/packages/76/e6/79b91e41bc8cc3e78ee95c87093c6cacfa275c786e53c9b11b9358026b3d/ruff-0.12.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139b3d28027987b78fc8d6cfb61165447bdf3740e650b7c480744873688808c2", size = 11363374, upload-time = "2025-06-17T15:19:05.875Z" }, + { url = "https://files.pythonhosted.org/packages/db/c3/82b292ff8a561850934549aa9dc39e2c4e783ab3c21debe55a495ddf7827/ruff-0.12.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68853e8517b17bba004152aebd9dd77d5213e503a5f2789395b25f26acac0da4", size = 11587647, upload-time = "2025-06-17T15:19:08.246Z" }, + { url = "https://files.pythonhosted.org/packages/2b/42/d5760d742669f285909de1bbf50289baccb647b53e99b8a3b4f7ce1b2001/ruff-0.12.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3a9512af224b9ac4757f7010843771da6b2b0935a9e5e76bb407caa901a1a514", size = 10527284, upload-time = "2025-06-17T15:19:10.37Z" }, + { url = "https://files.pythonhosted.org/packages/19/f6/fcee9935f25a8a8bba4adbae62495c39ef281256693962c2159e8b284c5f/ruff-0.12.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b08df3d96db798e5beb488d4df03011874aff919a97dcc2dd8539bb2be5d6a88", size = 10158609, upload-time = "2025-06-17T15:19:12.286Z" }, + { url = "https://files.pythonhosted.org/packages/37/fb/057febf0eea07b9384787bfe197e8b3384aa05faa0d6bd844b94ceb29945/ruff-0.12.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a315992297a7435a66259073681bb0d8647a826b7a6de45c6934b2ca3a9ed51", size = 11141462, upload-time = "2025-06-17T15:19:15.195Z" }, + { url = "https://files.pythonhosted.org/packages/10/7c/1be8571011585914b9d23c95b15d07eec2d2303e94a03df58294bc9274d4/ruff-0.12.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e55e44e770e061f55a7dbc6e9aed47feea07731d809a3710feda2262d2d4d8a", size = 11641616, upload-time = "2025-06-17T15:19:17.6Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ef/b960ab4818f90ff59e571d03c3f992828d4683561095e80f9ef31f3d58b7/ruff-0.12.0-py3-none-win32.whl", hash = "sha256:7162a4c816f8d1555eb195c46ae0bd819834d2a3f18f98cc63819a7b46f474fb", size = 10525289, upload-time = "2025-06-17T15:19:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/34/93/8b16034d493ef958a500f17cda3496c63a537ce9d5a6479feec9558f1695/ruff-0.12.0-py3-none-win_amd64.whl", hash = "sha256:d00b7a157b8fb6d3827b49d3324da34a1e3f93492c1f97b08e222ad7e9b291e0", size = 11598311, upload-time = "2025-06-17T15:19:21.785Z" }, + { url = "https://files.pythonhosted.org/packages/d0/33/4d3e79e4a84533d6cd526bfb42c020a23256ae5e4265d858bd1287831f7d/ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b", size = 10724946, upload-time = "2025-06-17T15:19:23.952Z" }, ] [[package]]