diff --git a/foxglove/client/api.py b/foxglove/client/api.py index f1deba3..4f0750d 100644 --- a/foxglove/client/api.py +++ b/foxglove/client/api.py @@ -2960,19 +2960,20 @@ def get_session( *, session_id: Optional[str] = None, session_key: Optional[str] = None, - project_id: str, + project_id: Optional[str] = None, ): """Fetches a single session. session_id: The ID of the session to fetch session_key: The key of the session to fetch project_id: The project ID to fetch the session from. + Required for multi-project organizations. """ identifier = _session_identifier_for_path(session_id, session_key) response = self.__session.get( self.__url__(f"/v1/sessions/{identifier}"), - params={"projectId": project_id}, + params=without_nulls({"projectId": project_id}), ) return _session_dict(json_or_raise(response)) @@ -2982,7 +2983,7 @@ def create_session( device_id: Optional[str] = None, key: Optional[str] = None, recording_ids: Optional[List[str]] = None, - properties: Optional[Dict[str, Union[str, bool, float, int]]] = None, + properties: Optional[Dict[str, Union[str, bool, float, int, List[str]]]] = None, ): """Creates a new session. @@ -3017,36 +3018,44 @@ def update_session( *, session_id: Optional[str] = None, session_key: Optional[str] = None, - project_id: str, - new_key: Optional[str] = None, + project_id: Optional[str] = None, + new_key: Any = _UNSET, add_recording_ids: Optional[List[str]] = None, remove_recording_ids: Optional[List[str]] = None, - properties: Optional[Dict[str, Union[str, bool, float, int]]] = None, + properties: Optional[ + Dict[str, Union[str, bool, float, int, List[str], None]] + ] = None, ): """Updates a session. session_id: The ID of the session to update. session_key: The current key of the session to update. project_id: The Project ID to which the session belongs. + Required for multi-project organizations. new_key: Optional new user-supplied identifier, unique within the project. + Pass ``new_key=None`` to clear the session's key. add_recording_ids: IDs of recordings to add to the session. remove_recording_ids: IDs of recordings to remove from the session. properties: Optional custom properties to add to or edit on the session. Each key must be defined as a custom property for your organization, - and each value must be of the appropriate type. + and each value must be of the appropriate type. A value of ``None`` + unsets that property; properties not included are unchanged. """ identifier = _session_identifier_for_path(session_id, session_key) - params = { - "key": new_key, - "addRecordingIds": add_recording_ids, - "removeRecordingIds": remove_recording_ids, - "properties": properties, - } + params = without_nulls( + { + "addRecordingIds": add_recording_ids, + "removeRecordingIds": remove_recording_ids, + "properties": properties, + } + ) + if new_key is not _UNSET: + params["key"] = new_key response = self.__session.patch( self.__url__(f"/v1/sessions/{identifier}"), - params={"projectId": project_id}, - json={k: v for k, v in params.items() if v is not None}, + params=without_nulls({"projectId": project_id}), + json=params, ) return _session_dict(json_or_raise(response)) @@ -3056,19 +3065,20 @@ def delete_session( *, session_id: Optional[str] = None, session_key: Optional[str] = None, - project_id: str, + project_id: Optional[str] = None, ): """Deletes a session. session_id: The ID of the session to delete. session_key: The key of the session to delete. project_id: The Project ID to which the session belongs. + Required for multi-project organizations. """ identifier = _session_identifier_for_path(session_id, session_key) response = self.__session.delete( self.__url__(f"/v1/sessions/{identifier}"), - params={"projectId": project_id}, + params=without_nulls({"projectId": project_id}), ) return json_or_raise(response) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 723a18b..a2ad6d9 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -255,6 +255,50 @@ def test_update_session_key_by_existing_key(): assert result["key"] == new_key +@responses.activate +def test_update_session_clears_key_and_property_without_project(): + session_id = fake.uuid4() + s = {**_make_session_json(session_id=session_id), "key": None} + responses.add( + responses.PATCH, + api_url(f"/v1/sessions/{session_id}"), + match=[ + query_string_matcher(""), + json_params_matcher({"key": None, "properties": {"vehicle": None}}), + ], + json=s, + ) + client = Client("test") + result = client.update_session( + session_id=session_id, + new_key=None, + properties={"vehicle": None}, + ) + assert result["id"] == session_id + assert result["key"] is None + + +@responses.activate +def test_get_and_delete_session_without_project(): + session_id = fake.uuid4() + s = _make_session_json(session_id=session_id) + responses.add( + responses.GET, + api_url(f"/v1/sessions/{session_id}"), + match=[query_string_matcher("")], + json=s, + ) + responses.add( + responses.DELETE, + api_url(f"/v1/sessions/{session_id}"), + match=[query_string_matcher("")], + json={"id": session_id}, + ) + client = Client("test") + assert client.get_session(session_id=session_id)["id"] == session_id + assert client.delete_session(session_id=session_id)["id"] == session_id + + @responses.activate def test_delete_session(): session_id = fake.uuid4()