From 66d171c1fdb1c73445aca4f1766bc982d013ebbc Mon Sep 17 00:00:00 2001 From: Michael Imas Date: Wed, 15 Jan 2025 13:17:04 +0200 Subject: [PATCH 1/5] updates fetch pagination and filtering --- setup.py | 7 +--- src/monday_sdk/modules/updates.py | 54 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index d93bc45..18a42e5 100644 --- a/setup.py +++ b/setup.py @@ -24,12 +24,7 @@ author_email="michaelim@monday.com", license_files=("LICENSE",), classifiers=[ # Optional - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - "Development Status :: 3 - Alpha", - # Indicate who your project is intended for + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Topic :: Software Development :: Build Tools", # Pick your license as you wish diff --git a/src/monday_sdk/modules/updates.py b/src/monday_sdk/modules/updates.py index 9be1388..63d8fba 100644 --- a/src/monday_sdk/modules/updates.py +++ b/src/monday_sdk/modules/updates.py @@ -26,3 +26,57 @@ def fetch_board_updates(self, board_id, limit=100, page=1) -> List[Update]: query = get_updates_for_board(board_id, limit, page) response: MondayApiResponse = self.execute(query) return response.data.boards[0].updates + + def fetch_all_board_updates( + self, + board_id: int, + limit: int = 100, + updated_before: Optional[datetime] = None, + updated_after: Optional[datetime] = None, + ) -> List[Update]: + """ + Fetches updates from the given board across ALL pages, automatically + paginating until no more updates are returned. Optionally filters by + `updated_before` and/or `updated_after`. + + :param board_id: The ID of the board to retrieve updates from. + :param limit: The number of updates per page. + :param updated_before: Return only updates with `updated_at` <= this datetime. + :param updated_after: Return only updates with `updated_at` >= this datetime. + :return: A list of updates, each represented as a dict (or your custom Update type). + """ + all_updates: List[Update] = [] + page = 1 + + while True: + # 1) Fetch a single page of updates using the existing method + updates = self.fetch_board_updates(board_id, limit=limit, page=page) + if not updates: + # If we get an empty list, we've reached the end of the results + break + + # 2) Filter by updated_before / updated_after if provided + filtered_updates = [] + for update in updates: + updated_at_str = update.get("updated_at") + if not updated_at_str: + # If somehow there's no 'updated_at', skip it + continue + + updated_time = dateutil.parser.isoparse(updated_at_str) + # If updated_before is provided, skip if update is AFTER that date + if updated_before and updated_time > updated_before: + continue + # If updated_after is provided, skip if update is BEFORE that date + if updated_after and updated_time < updated_after: + continue + + filtered_updates.append(update) + + # 3) Accumulate the filtered updates + all_updates.extend(filtered_updates) + + # 4) Move to next page + page += 1 + + return all_updates \ No newline at end of file From 75422446ee2d12de9445cc936d1dc77c7db649d8 Mon Sep 17 00:00:00 2001 From: Michael Imas Date: Wed, 15 Jan 2025 18:35:41 +0200 Subject: [PATCH 2/5] updates fetch pagination and filtering, improved --- src/monday_sdk/modules/updates.py | 69 ++++++++-------------- src/monday_sdk/types/api_response_types.py | 1 + 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/monday_sdk/modules/updates.py b/src/monday_sdk/modules/updates.py index 63d8fba..fdb5a1a 100644 --- a/src/monday_sdk/modules/updates.py +++ b/src/monday_sdk/modules/updates.py @@ -1,10 +1,10 @@ -from typing import List +from datetime import datetime +from typing import List, Optional from ..query_templates import create_update_query, delete_update_query, get_update_query, get_updates_for_item_query, get_updates_for_board from ..types import MondayApiResponse, Update from ..graphql_handler import MondayGraphQL - class UpdateModule(MondayGraphQL): def create_update(self, item_id, update_value) -> MondayApiResponse: query = create_update_query(item_id, update_value) @@ -22,61 +22,44 @@ def fetch_updates_for_item(self, item_id, limit=100) -> MondayApiResponse: query = get_updates_for_item_query(item_id=item_id, limit=limit) return self.execute(query) - def fetch_board_updates(self, board_id, limit=100, page=1) -> List[Update]: + def fetch_board_updates_page(self, board_id, limit=100, page=1) -> List[Update]: query = get_updates_for_board(board_id, limit, page) response: MondayApiResponse = self.execute(query) return response.data.boards[0].updates - def fetch_all_board_updates( + def fetch_board_updates( self, - board_id: int, - limit: int = 100, - updated_before: Optional[datetime] = None, - updated_after: Optional[datetime] = None, + board_ids: str, + updated_after: Optional[str] = None, + updated_before: Optional[str] = None, ) -> List[Update]: """ - Fetches updates from the given board across ALL pages, automatically - paginating until no more updates are returned. Optionally filters by - `updated_before` and/or `updated_after`. - - :param board_id: The ID of the board to retrieve updates from. - :param limit: The number of updates per page. - :param updated_before: Return only updates with `updated_at` <= this datetime. - :param updated_after: Return only updates with `updated_at` >= this datetime. - :return: A list of updates, each represented as a dict (or your custom Update type). + Fetches all updates from a board (with optional date filtering). + - Paginates through all pages until no more updates. + - If from_date or to_date are provided, filters out updates outside that window. """ - all_updates: List[Update] = [] + start_dt = datetime.fromisoformat(updated_after) if updated_after else None + end_dt = datetime.fromisoformat(updated_before) if updated_before else None + + all_updates = [] page = 1 while True: - # 1) Fetch a single page of updates using the existing method - updates = self.fetch_board_updates(board_id, limit=limit, page=page) + updates = self.fetch_board_updates_page(board_ids, page=page) if not updates: - # If we get an empty list, we've reached the end of the results break - # 2) Filter by updated_before / updated_after if provided - filtered_updates = [] - for update in updates: - updated_at_str = update.get("updated_at") - if not updated_at_str: - # If somehow there's no 'updated_at', skip it - continue - - updated_time = dateutil.parser.isoparse(updated_at_str) - # If updated_before is provided, skip if update is AFTER that date - if updated_before and updated_time > updated_before: - continue - # If updated_after is provided, skip if update is BEFORE that date - if updated_after and updated_time < updated_after: - continue - - filtered_updates.append(update) - - # 3) Accumulate the filtered updates - all_updates.extend(filtered_updates) - - # 4) Move to next page + if start_dt or end_dt: + updates = [ + u for u in updates + if ( + u.updated_at + and (start_dt is None or datetime.fromisoformat(u.updated_at) >= start_dt) + and (end_dt is None or datetime.fromisoformat(u.updated_at) <= end_dt) + ) + ] + + all_updates.extend(updates) page += 1 return all_updates \ No newline at end of file diff --git a/src/monday_sdk/types/api_response_types.py b/src/monday_sdk/types/api_response_types.py index c1f405b..a7a60a8 100644 --- a/src/monday_sdk/types/api_response_types.py +++ b/src/monday_sdk/types/api_response_types.py @@ -46,6 +46,7 @@ class Update: text_body: Optional[str] = field(default=None) item_id: Optional[str] = field(default=None) created_at: Optional[str] = field(default=None) + updated_at: Optional[str] = field(default=None) creator: Optional[User] = field(default=None) From 46e0895cb0eef1035a53e8d8784392d4a3cbd012 Mon Sep 17 00:00:00 2001 From: Michael Imas Date: Wed, 15 Jan 2025 18:38:20 +0200 Subject: [PATCH 3/5] minor version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 18a42e5..df9c776 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name="monday-api-python-sdk", # Required - version="1.1.3", # Required + version="1.2.3", # Required description="A Python SDK for interacting with Monday's GraphQL API", # Optional long_description=long_description, # Optional long_description_content_type="text/markdown", # Optional (see note above) From 75f6e1f4570ebb2bb122f61084b701fca2aea214 Mon Sep 17 00:00:00 2001 From: Michael Imas Date: Wed, 15 Jan 2025 18:55:52 +0200 Subject: [PATCH 4/5] readme updates --- README.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c0d5ffc..71488b6 100644 --- a/README.md +++ b/README.md @@ -102,21 +102,11 @@ The SDK provides structured types to help you work with API responses more effec Here is an example of how to use these types with the SDK to deserialize API responses: ```python -from monday_sdk import MondayClient, MondayApiResponse -import dacite +from monday_sdk import MondayClient client = MondayClient(token="your_token") - -# Fetch the raw response data -response_data = client.boards.fetch_all_items_by_board_id(board_id="your_board_id") - -# Deserialize the response data into typed objects -monday_response = dacite.from_dict(data_class=MondayApiResponse, data=response_data) - -# Access specific fields using the deserialized objects -first_board = monday_response.data.boards[0] -first_item_name = first_board.items_page.items[0].name - +items = client.boards.fetch_all_items_by_board_id(board_id="your_board_id") +first_item_name = items[0].name print(f"First item name: {first_item_name}") ``` By using these types, you can ensure type safety and better code completion support in your IDE, making your work with the Monday API more efficient and error-free. From 5559bfe1dec1ddd44466ff4416556c5e23c5f366 Mon Sep 17 00:00:00 2001 From: Michael Imas Date: Wed, 15 Jan 2025 19:01:24 +0200 Subject: [PATCH 5/5] retrieve updated_at --- src/monday_sdk/query_templates.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/monday_sdk/query_templates.py b/src/monday_sdk/query_templates.py index 0b6ab0d..4236bac 100644 --- a/src/monday_sdk/query_templates.py +++ b/src/monday_sdk/query_templates.py @@ -552,6 +552,7 @@ def get_updates_for_board(board_id, limit: int, page=1): id, text_body, item_id, + updated_at, created_at, creator { name,