From 4c4b458834f3044f8b18c231e8175ee8749dec85 Mon Sep 17 00:00:00 2001 From: Ruben Domingo Gaspar Aparicio Date: Mon, 9 Feb 2026 23:29:31 +0100 Subject: [PATCH 1/4] Allow to call streaming status with a settings object --- .pre-commit-config.yaml | 9 ++++--- .vscode/settings.json | 13 ++++------ README.md | 2 +- example/get_meeting_livestream.py | 4 +-- example/get_rooms.py | 4 ++- example/start_meeting_livestream.py | 26 +++++++++++++++++++ requirements.txt | 3 ++- .../test_meeting_livestreams_component.py | 17 +++++++++++- .../test_webinar_livestreams_component.py | 17 +++++++++++- .../meeting_livestreams_component.py | 14 ++++++++-- .../webinar_livestreams_component.py | 14 ++++++++-- .../utils/typed_dict_parameters.py | 2 +- 12 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 example/start_meeting_livestream.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c9ed6d7..2295192 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,20 +1,21 @@ repos: - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 26.1.0 hooks: - id: black - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 7.0.0 hooks: - id: isort name: isort args: [--profile, black, --skip, migrations] - repo: https://github.com/pycqa/flake8 - rev: "6.0.0" # pick a git hash / tag to point to + rev: "7.3.0" hooks: - id: flake8 + additional_dependencies: ["pyflakes>=3.2.0"] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.2.0" + rev: "v1.19.1" hooks: - id: mypy args: [--no-strict-optional, --ignore-missing-imports] diff --git a/.vscode/settings.json b/.vscode/settings.json index f0f682a..df863d7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,10 +24,7 @@ "python.analysis.inlayHints.functionReturnTypes": true, "editor.formatOnSave": true, "isort.check": true, - "isort.args": [ - "--profile", - "black" - ], + "isort.args": ["--profile", "black"], "python.testing.pytestEnabled": true, "python.testing.pytestArgs": [ "tests", @@ -38,7 +35,7 @@ ], "[python]": { "editor.codeActionsOnSave": { - "source.organizeImports": true + "source.organizeImports": "explicit" }, "editor.defaultFormatter": "ms-python.black-formatter", "editor.codeLens": true @@ -50,6 +47,6 @@ "files.exclude": { "**/__pycache__": true, "**/.pytest_cache": true, - "**/.mypy*": true, - }, -} \ No newline at end of file + "**/.mypy*": true + } +} diff --git a/README.md b/README.md index 2e452b2..c7da040 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ setup_logs(log_level=logging.DEBUG) 1. get webinar live stream 2. update webinar live stream -3. update webinar livestream status +3. update webinar livestream status - Following [Zoom documentation](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetingLiveStreamStatusUpdate). ### **zoom rooms**: diff --git a/example/get_meeting_livestream.py b/example/get_meeting_livestream.py index b225fa1..f4e4079 100644 --- a/example/get_meeting_livestream.py +++ b/example/get_meeting_livestream.py @@ -9,7 +9,5 @@ MEETING_ID = os.environ["MEETING_ID"] -result = zoom_client.meeting_livestreams.get_livestream( - MEETING_ID, -) +result = zoom_client.meeting_livestreams.get_livestream(MEETING_ID) print(result) diff --git a/example/get_rooms.py b/example/get_rooms.py index adbe573..298ac2e 100644 --- a/example/get_rooms.py +++ b/example/get_rooms.py @@ -9,7 +9,9 @@ logger = setup_logs(log_level=logging.DEBUG) -zoom_client = ZoomApiClient.init_from_dotenv(use_path=".") +zoom_client = ZoomApiClient.init_from_dotenv( + use_path="." +) parameters = RoomsListDict( type=RoomType.ZOOM_ROOM, diff --git a/example/start_meeting_livestream.py b/example/start_meeting_livestream.py new file mode 100644 index 0000000..a91c8e3 --- /dev/null +++ b/example/start_meeting_livestream.py @@ -0,0 +1,26 @@ +import logging +import os + +from zoom_python_client.utils.logger import setup_logs +from zoom_python_client.zoom_api_client import ZoomApiClient + +setup_logs(log_level=logging.DEBUG) +zoom_client = ZoomApiClient.init_from_dotenv() +MEETING_ID = os.environ["MEETING_ID"] + + +result = zoom_client.meeting_livestreams.get_livestream(MEETING_ID) +print(result) + +settings = { + "active_speaker_name": False, + "display_name": "CERN_Webcast_Service", + "layout": "follow_host", + "close_caption": "embedded", +} +started = zoom_client.meeting_livestreams.update_livestream_status( + MEETING_ID, + "start", + settings=settings, +) +print(started) diff --git a/requirements.txt b/requirements.txt index 4deb882..49c3108 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ python-dotenv==1.0.0 requests==2.31.0 -typing_extensions==4.7.1 \ No newline at end of file +typing_extensions==4.7.1 +typed-ast==1.5.5 \ No newline at end of file diff --git a/tests/zoom_python_client/client_components/meeting_livestreams/test_meeting_livestreams_component.py b/tests/zoom_python_client/client_components/meeting_livestreams/test_meeting_livestreams_component.py index f724f21..0e47bea 100644 --- a/tests/zoom_python_client/client_components/meeting_livestreams/test_meeting_livestreams_component.py +++ b/tests/zoom_python_client/client_components/meeting_livestreams/test_meeting_livestreams_component.py @@ -81,14 +81,29 @@ def test_update_meeting_livestreams_component_no_response(self): @responses.activate def test_update_meeting_livestreams_status_component(self): + settings = { + "active_speaker_name": False, + "display_name": "CERN_Webcast_Service", + "layout": "follow_host", + "close_caption": "embedded", + } responses.add( responses.PATCH, "http://localhost/meetings/12345/livestream/status", status=204, + match=[ + responses.matchers.json_params_matcher( + {"action": "start", "settings": settings} + ) + ], ) zoom_client = ZoomApiClient("aaa", "bbb", "ccc", "http://localhost") component = MeetingLiveStreamsComponent(zoom_client) - result = component.update_livestream_status("12345", "start") + result = component.update_livestream_status( + "12345", + "start", + settings=settings, + ) assert result @responses.activate diff --git a/tests/zoom_python_client/client_components/webinar_livestreams/test_webinar_livestreams_component.py b/tests/zoom_python_client/client_components/webinar_livestreams/test_webinar_livestreams_component.py index 2167310..d76acc3 100644 --- a/tests/zoom_python_client/client_components/webinar_livestreams/test_webinar_livestreams_component.py +++ b/tests/zoom_python_client/client_components/webinar_livestreams/test_webinar_livestreams_component.py @@ -81,14 +81,29 @@ def test_update_webinar_livestreams_component_no_response(self): @responses.activate def test_update_webinar_livestreams_status_component(self): + settings = { + "active_speaker_name": False, + "display_name": "CERN_Webcast_Service", + "layout": "follow_host", + "close_caption": "embedded", + } responses.add( responses.PATCH, "http://localhost/webinars/12345/livestream/status", status=204, + match=[ + responses.matchers.json_params_matcher( + {"action": "start", "settings": settings} + ) + ], ) zoom_client = ZoomApiClient("aaa", "bbb", "ccc", "http://localhost") component = WebinarLiveStreamsComponent(zoom_client) - result = component.update_livestream_status("12345", "start") + result = component.update_livestream_status( + "12345", + "start", + settings=settings, + ) assert result @responses.activate diff --git a/zoom_python_client/client_components/meeting_livestreams/meeting_livestreams_component.py b/zoom_python_client/client_components/meeting_livestreams/meeting_livestreams_component.py index 6262c62..23734ad 100644 --- a/zoom_python_client/client_components/meeting_livestreams/meeting_livestreams_component.py +++ b/zoom_python_client/client_components/meeting_livestreams/meeting_livestreams_component.py @@ -1,5 +1,7 @@ from json import JSONDecodeError -from typing import TypedDict +from typing import Any, Dict, Optional + +from typing_extensions import NotRequired, TypedDict from zoom_python_client.zoom_auth_api.zoom_auth_api_client import ZoomAuthApiClientError from zoom_python_client.zoom_client_interface import ZoomClientInterface @@ -14,6 +16,7 @@ class LiveStreamDict(TypedDict): class LiveStreamStatusDict(TypedDict): action: str + settings: NotRequired[Dict[str, Any]] class MeetingLiveStreamsComponent: @@ -41,9 +44,16 @@ def update_livestream(self, meeting_id: str, data: LiveStreamDict) -> bool: return True return False - def update_livestream_status(self, meeting_id: str, action: str) -> bool: + def update_livestream_status( + self, + meeting_id: str, + action: str, + settings: Optional[Dict[str, Any]] = None, + ) -> bool: api_path = f"/meetings/{meeting_id}/livestream/status" data: LiveStreamStatusDict = {"action": action} + if settings is not None: + data["settings"] = settings response = self.client.make_patch_request(api_path, data) if response and response.status_code == 204: return True diff --git a/zoom_python_client/client_components/webinar_livestreams/webinar_livestreams_component.py b/zoom_python_client/client_components/webinar_livestreams/webinar_livestreams_component.py index 9f5b5c8..8702afc 100644 --- a/zoom_python_client/client_components/webinar_livestreams/webinar_livestreams_component.py +++ b/zoom_python_client/client_components/webinar_livestreams/webinar_livestreams_component.py @@ -1,5 +1,7 @@ from json import JSONDecodeError -from typing import TypedDict +from typing import Any, Dict, Optional + +from typing_extensions import NotRequired, TypedDict from zoom_python_client.zoom_auth_api.zoom_auth_api_client import ZoomAuthApiClientError from zoom_python_client.zoom_client_interface import ZoomClientInterface @@ -14,6 +16,7 @@ class LiveStreamDict(TypedDict): class LiveStreamStatusDict(TypedDict): action: str + settings: NotRequired[Dict[str, Any]] class WebinarLiveStreamsComponent: @@ -38,9 +41,16 @@ def update_livestream(self, meeting_id: str, data: LiveStreamDict) -> bool: return True return False - def update_livestream_status(self, meeting_id: str, action: str) -> bool: + def update_livestream_status( + self, + meeting_id: str, + action: str, + settings: Optional[Dict[str, Any]] = None, + ) -> bool: api_path = f"/webinars/{meeting_id}/livestream/status" data: LiveStreamStatusDict = {"action": action} + if settings is not None: + data["settings"] = settings response = self.client.make_patch_request(api_path, data) if response.status_code == 204: return True diff --git a/zoom_python_client/utils/typed_dict_parameters.py b/zoom_python_client/utils/typed_dict_parameters.py index b958304..889762c 100644 --- a/zoom_python_client/utils/typed_dict_parameters.py +++ b/zoom_python_client/utils/typed_dict_parameters.py @@ -6,7 +6,7 @@ class DataType(TypedDict, total=False): - ... + pass def generate_parameters_dict(data: DataType) -> dict: From 1f8976268b0924f2aeed1d718d3b8efe3e68b95a Mon Sep 17 00:00:00 2001 From: Rene Fernandez Date: Tue, 17 Feb 2026 09:29:27 +0100 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9C=A8=20Add=20.DS=5FStore=20to=20.gitig?= =?UTF-8?q?nore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b2679c7..40bfdfd 100644 --- a/.gitignore +++ b/.gitignore @@ -162,3 +162,4 @@ cython_debug/ # Names of the files where access token and expire seconds are stored access_token expire_seconds +.DS_Store From 5197bba2dacc38b410f71fa172c80d4e7806f11b Mon Sep 17 00:00:00 2001 From: Rene Fernandez Date: Tue, 17 Feb 2026 09:30:15 +0100 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=9A=80=20Bump=20version=20to=200.2.3?= =?UTF-8?q?=20in=20pyproject.toml=20and=20add=20CHANGELOG.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e8d0b11 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,122 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.2.3] - 2026-02-17 + +### Changed +- Allow calling streaming status with a settings object (support for transcriptions) + +## [0.2.2] - 2023-08-30 + +### Added +- Calendars component for interacting with Zoom calendar resources +- Tests for calendars component +- Example script for interacting with calendars + +### Changed +- Updated documentation with new calendar endpoints + +## [0.2.1] - 2023-08-29 + +### Changed +- Upgraded project dependencies +- Updated dev dependencies + +### Fixed +- Fixed test returning content on 204 status +- Removed debug logging from production code + +## [0.2.0] - 2023-07-12 + +### Added +- Zoom Rooms component for interacting with Zoom Rooms API +- Example script to interact with Zoom Rooms +- Tests for Rooms component +- Utility function to create dict from TypedDict with NotRequired fields + +### Changed +- Improved typed dict parameters to work with `from` and `to` date fields +- Renamed `generate_parameters_dict` function +- Simplified `get_project_dir()` function + +### Fixed +- Fixed typo in import inside example in README +- Fixed typo in CONTRIBUTING.md + +## [0.1.1] - 2023-06-01 + +### Added +- Retry mechanism for generating a new token on 401 responses +- Support for loading/saving access token from/to file system +- Poetry for dependency management + +### Changed +- Changed LICENSE to MIT +- Set minimum dependencies instead of strict versions +- Lowered minimum required requests version to 2.23.0 +- Added Pypi install instructions to README +- Published beta version on PyPI + +## [0.1.0] - 2023-05-30 + +### Changed +- Set minimum dependencies instead of strict versions + +## [0.0.6] - 2023-05-30 + +### Added +- Support for loading and saving access token from/to file + +## [0.0.5] - 2023-05-22 + +### Changed +- Lowered the minimum required requests version to 2.23.0 + +## [0.0.4] - 2023-05-15 + +### Added +- Retry mechanism on 401 unauthorized responses + +## [0.0.3] - 2023-05-05 + +### Added +- Resolution parameter support for live streams + +## [0.0.2] - 2023-05-05 + +### Added +- Meeting token endpoint (`get_meeting_token`) +- Updated workflows + +## [0.0.1] - 2023-05-05 + +### Added +- Initial release +- Server-to-Server OAuth token support +- `ZoomApiClient` with `init_from_env` and `init_from_dotenv` methods +- Users component with `get_user` and `get_user_meetings` endpoints +- Meetings component with `get_meeting` endpoint +- Meeting livestreams component +- Webinars component +- Webinar livestreams component +- Logging utilities +- Pre-commit hooks with mypy, isort, flake8, and black +- GitHub Actions for testing, pre-commit, and CodeQL analysis +- Code coverage reporting with codecov + +[0.2.3]: https://github.com/cern-vc/zoom-python-client/compare/v0.2.2...v0.2.3 +[0.2.2]: https://github.com/cern-vc/zoom-python-client/compare/v0.2.1...v0.2.2 +[0.2.1]: https://github.com/cern-vc/zoom-python-client/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/cern-vc/zoom-python-client/compare/v0.1.1...v0.2.0 +[0.1.1]: https://github.com/cern-vc/zoom-python-client/compare/v0.1.0...v0.1.1 +[0.1.0]: https://github.com/cern-vc/zoom-python-client/compare/v0.0.6...v0.1.0 +[0.0.6]: https://github.com/cern-vc/zoom-python-client/compare/0.0.5...v0.0.6 +[0.0.5]: https://github.com/cern-vc/zoom-python-client/compare/0.0.4...0.0.5 +[0.0.4]: https://github.com/cern-vc/zoom-python-client/compare/0.0.3...0.0.4 +[0.0.3]: https://github.com/cern-vc/zoom-python-client/compare/0.0.2...0.0.3 +[0.0.2]: https://github.com/cern-vc/zoom-python-client/compare/0.0.1...0.0.2 +[0.0.1]: https://github.com/cern-vc/zoom-python-client/releases/tag/0.0.1 diff --git a/pyproject.toml b/pyproject.toml index 459df3c..2bf6ac0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "zoom-python-client" -version = "0.2.2" +version = "0.2.3" authors = ["Rene Fernandez Sanchez "] maintainers = [ "Rene Fernandez Sanchez ", From 8ac040192794a5288f0bd3204ab0fe7eb16d8f82 Mon Sep 17 00:00:00 2001 From: Rene Fernandez Date: Tue, 17 Feb 2026 09:33:10 +0100 Subject: [PATCH 4/4] =?UTF-8?q?=E2=9C=A8=20Fix=20formatting=20issue=20on?= =?UTF-8?q?=20get=5Frooms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/get_rooms.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/example/get_rooms.py b/example/get_rooms.py index 298ac2e..adbe573 100644 --- a/example/get_rooms.py +++ b/example/get_rooms.py @@ -9,9 +9,7 @@ logger = setup_logs(log_level=logging.DEBUG) -zoom_client = ZoomApiClient.init_from_dotenv( - use_path="." -) +zoom_client = ZoomApiClient.init_from_dotenv(use_path=".") parameters = RoomsListDict( type=RoomType.ZOOM_ROOM,