universal-mcp-applications 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- universal_mcp/applications/ahrefs/README.md +51 -0
- universal_mcp/applications/ahrefs/__init__.py +1 -0
- universal_mcp/applications/ahrefs/app.py +2291 -0
- universal_mcp/applications/airtable/README.md +22 -0
- universal_mcp/applications/airtable/__init__.py +1 -0
- universal_mcp/applications/airtable/app.py +479 -0
- universal_mcp/applications/apollo/README.md +44 -0
- universal_mcp/applications/apollo/__init__.py +1 -0
- universal_mcp/applications/apollo/app.py +1847 -0
- universal_mcp/applications/asana/README.md +199 -0
- universal_mcp/applications/asana/__init__.py +1 -0
- universal_mcp/applications/asana/app.py +9509 -0
- universal_mcp/applications/aws-s3/README.md +0 -0
- universal_mcp/applications/aws-s3/__init__.py +1 -0
- universal_mcp/applications/aws-s3/app.py +552 -0
- universal_mcp/applications/bill/README.md +0 -0
- universal_mcp/applications/bill/__init__.py +1 -0
- universal_mcp/applications/bill/app.py +8705 -0
- universal_mcp/applications/box/README.md +307 -0
- universal_mcp/applications/box/__init__.py +1 -0
- universal_mcp/applications/box/app.py +15987 -0
- universal_mcp/applications/braze/README.md +106 -0
- universal_mcp/applications/braze/__init__.py +1 -0
- universal_mcp/applications/braze/app.py +4754 -0
- universal_mcp/applications/cal-com-v2/README.md +150 -0
- universal_mcp/applications/cal-com-v2/__init__.py +1 -0
- universal_mcp/applications/cal-com-v2/app.py +5541 -0
- universal_mcp/applications/calendly/README.md +53 -0
- universal_mcp/applications/calendly/__init__.py +1 -0
- universal_mcp/applications/calendly/app.py +1436 -0
- universal_mcp/applications/canva/README.md +43 -0
- universal_mcp/applications/canva/__init__.py +1 -0
- universal_mcp/applications/canva/app.py +941 -0
- universal_mcp/applications/clickup/README.md +135 -0
- universal_mcp/applications/clickup/__init__.py +1 -0
- universal_mcp/applications/clickup/app.py +5009 -0
- universal_mcp/applications/coda/README.md +108 -0
- universal_mcp/applications/coda/__init__.py +1 -0
- universal_mcp/applications/coda/app.py +3671 -0
- universal_mcp/applications/confluence/README.md +198 -0
- universal_mcp/applications/confluence/__init__.py +1 -0
- universal_mcp/applications/confluence/app.py +6273 -0
- universal_mcp/applications/contentful/README.md +17 -0
- universal_mcp/applications/contentful/__init__.py +1 -0
- universal_mcp/applications/contentful/app.py +364 -0
- universal_mcp/applications/crustdata/README.md +25 -0
- universal_mcp/applications/crustdata/__init__.py +1 -0
- universal_mcp/applications/crustdata/app.py +586 -0
- universal_mcp/applications/dialpad/README.md +202 -0
- universal_mcp/applications/dialpad/__init__.py +1 -0
- universal_mcp/applications/dialpad/app.py +5949 -0
- universal_mcp/applications/digitalocean/README.md +463 -0
- universal_mcp/applications/digitalocean/__init__.py +1 -0
- universal_mcp/applications/digitalocean/app.py +20835 -0
- universal_mcp/applications/domain-checker/README.md +13 -0
- universal_mcp/applications/domain-checker/__init__.py +1 -0
- universal_mcp/applications/domain-checker/app.py +265 -0
- universal_mcp/applications/e2b/README.md +12 -0
- universal_mcp/applications/e2b/__init__.py +1 -0
- universal_mcp/applications/e2b/app.py +187 -0
- universal_mcp/applications/elevenlabs/README.md +88 -0
- universal_mcp/applications/elevenlabs/__init__.py +1 -0
- universal_mcp/applications/elevenlabs/app.py +3235 -0
- universal_mcp/applications/exa/README.md +15 -0
- universal_mcp/applications/exa/__init__.py +1 -0
- universal_mcp/applications/exa/app.py +221 -0
- universal_mcp/applications/falai/README.md +17 -0
- universal_mcp/applications/falai/__init__.py +1 -0
- universal_mcp/applications/falai/app.py +331 -0
- universal_mcp/applications/figma/README.md +49 -0
- universal_mcp/applications/figma/__init__.py +1 -0
- universal_mcp/applications/figma/app.py +1090 -0
- universal_mcp/applications/firecrawl/README.md +20 -0
- universal_mcp/applications/firecrawl/__init__.py +1 -0
- universal_mcp/applications/firecrawl/app.py +514 -0
- universal_mcp/applications/fireflies/README.md +25 -0
- universal_mcp/applications/fireflies/__init__.py +1 -0
- universal_mcp/applications/fireflies/app.py +506 -0
- universal_mcp/applications/fpl/README.md +23 -0
- universal_mcp/applications/fpl/__init__.py +1 -0
- universal_mcp/applications/fpl/app.py +1327 -0
- universal_mcp/applications/fpl/utils/api.py +142 -0
- universal_mcp/applications/fpl/utils/fixtures.py +629 -0
- universal_mcp/applications/fpl/utils/helper.py +982 -0
- universal_mcp/applications/fpl/utils/league_utils.py +546 -0
- universal_mcp/applications/fpl/utils/position_utils.py +68 -0
- universal_mcp/applications/ghost-content/README.md +25 -0
- universal_mcp/applications/ghost-content/__init__.py +1 -0
- universal_mcp/applications/ghost-content/app.py +654 -0
- universal_mcp/applications/github/README.md +1049 -0
- universal_mcp/applications/github/__init__.py +1 -0
- universal_mcp/applications/github/app.py +50600 -0
- universal_mcp/applications/gong/README.md +63 -0
- universal_mcp/applications/gong/__init__.py +1 -0
- universal_mcp/applications/gong/app.py +2297 -0
- universal_mcp/applications/google-ads/README.md +0 -0
- universal_mcp/applications/google-ads/__init__.py +1 -0
- universal_mcp/applications/google-ads/app.py +23 -0
- universal_mcp/applications/google-calendar/README.md +21 -0
- universal_mcp/applications/google-calendar/__init__.py +1 -0
- universal_mcp/applications/google-calendar/app.py +574 -0
- universal_mcp/applications/google-docs/README.md +25 -0
- universal_mcp/applications/google-docs/__init__.py +1 -0
- universal_mcp/applications/google-docs/app.py +760 -0
- universal_mcp/applications/google-drive/README.md +68 -0
- universal_mcp/applications/google-drive/__init__.py +1 -0
- universal_mcp/applications/google-drive/app.py +4936 -0
- universal_mcp/applications/google-gemini/README.md +25 -0
- universal_mcp/applications/google-gemini/__init__.py +1 -0
- universal_mcp/applications/google-gemini/app.py +663 -0
- universal_mcp/applications/google-mail/README.md +31 -0
- universal_mcp/applications/google-mail/__init__.py +1 -0
- universal_mcp/applications/google-mail/app.py +1354 -0
- universal_mcp/applications/google-searchconsole/README.md +21 -0
- universal_mcp/applications/google-searchconsole/__init__.py +1 -0
- universal_mcp/applications/google-searchconsole/app.py +320 -0
- universal_mcp/applications/google-sheet/README.md +36 -0
- universal_mcp/applications/google-sheet/__init__.py +1 -0
- universal_mcp/applications/google-sheet/app.py +1941 -0
- universal_mcp/applications/hashnode/README.md +20 -0
- universal_mcp/applications/hashnode/__init__.py +1 -0
- universal_mcp/applications/hashnode/app.py +455 -0
- universal_mcp/applications/heygen/README.md +44 -0
- universal_mcp/applications/heygen/__init__.py +1 -0
- universal_mcp/applications/heygen/app.py +961 -0
- universal_mcp/applications/http-tools/README.md +16 -0
- universal_mcp/applications/http-tools/__init__.py +1 -0
- universal_mcp/applications/http-tools/app.py +153 -0
- universal_mcp/applications/hubspot/README.md +239 -0
- universal_mcp/applications/hubspot/__init__.py +1 -0
- universal_mcp/applications/hubspot/app.py +416 -0
- universal_mcp/applications/jira/README.md +600 -0
- universal_mcp/applications/jira/__init__.py +1 -0
- universal_mcp/applications/jira/app.py +28804 -0
- universal_mcp/applications/klaviyo/README.md +313 -0
- universal_mcp/applications/klaviyo/__init__.py +1 -0
- universal_mcp/applications/klaviyo/app.py +11236 -0
- universal_mcp/applications/linkedin/README.md +15 -0
- universal_mcp/applications/linkedin/__init__.py +1 -0
- universal_mcp/applications/linkedin/app.py +243 -0
- universal_mcp/applications/mailchimp/README.md +281 -0
- universal_mcp/applications/mailchimp/__init__.py +1 -0
- universal_mcp/applications/mailchimp/app.py +10937 -0
- universal_mcp/applications/markitdown/README.md +12 -0
- universal_mcp/applications/markitdown/__init__.py +1 -0
- universal_mcp/applications/markitdown/app.py +63 -0
- universal_mcp/applications/miro/README.md +151 -0
- universal_mcp/applications/miro/__init__.py +1 -0
- universal_mcp/applications/miro/app.py +5429 -0
- universal_mcp/applications/ms-teams/README.md +42 -0
- universal_mcp/applications/ms-teams/__init__.py +1 -0
- universal_mcp/applications/ms-teams/app.py +1823 -0
- universal_mcp/applications/neon/README.md +74 -0
- universal_mcp/applications/neon/__init__.py +1 -0
- universal_mcp/applications/neon/app.py +2018 -0
- universal_mcp/applications/notion/README.md +30 -0
- universal_mcp/applications/notion/__init__.py +1 -0
- universal_mcp/applications/notion/app.py +527 -0
- universal_mcp/applications/openai/README.md +22 -0
- universal_mcp/applications/openai/__init__.py +1 -0
- universal_mcp/applications/openai/app.py +759 -0
- universal_mcp/applications/outlook/README.md +20 -0
- universal_mcp/applications/outlook/__init__.py +1 -0
- universal_mcp/applications/outlook/app.py +444 -0
- universal_mcp/applications/perplexity/README.md +12 -0
- universal_mcp/applications/perplexity/__init__.py +1 -0
- universal_mcp/applications/perplexity/app.py +65 -0
- universal_mcp/applications/pipedrive/README.md +284 -0
- universal_mcp/applications/pipedrive/__init__.py +1 -0
- universal_mcp/applications/pipedrive/app.py +12924 -0
- universal_mcp/applications/posthog/README.md +132 -0
- universal_mcp/applications/posthog/__init__.py +1 -0
- universal_mcp/applications/posthog/app.py +7125 -0
- universal_mcp/applications/reddit/README.md +135 -0
- universal_mcp/applications/reddit/__init__.py +1 -0
- universal_mcp/applications/reddit/app.py +4652 -0
- universal_mcp/applications/replicate/README.md +18 -0
- universal_mcp/applications/replicate/__init__.py +1 -0
- universal_mcp/applications/replicate/app.py +495 -0
- universal_mcp/applications/resend/README.md +40 -0
- universal_mcp/applications/resend/__init__.py +1 -0
- universal_mcp/applications/resend/app.py +881 -0
- universal_mcp/applications/retell/README.md +21 -0
- universal_mcp/applications/retell/__init__.py +1 -0
- universal_mcp/applications/retell/app.py +333 -0
- universal_mcp/applications/rocketlane/README.md +70 -0
- universal_mcp/applications/rocketlane/__init__.py +1 -0
- universal_mcp/applications/rocketlane/app.py +4346 -0
- universal_mcp/applications/semanticscholar/README.md +25 -0
- universal_mcp/applications/semanticscholar/__init__.py +1 -0
- universal_mcp/applications/semanticscholar/app.py +482 -0
- universal_mcp/applications/semrush/README.md +44 -0
- universal_mcp/applications/semrush/__init__.py +1 -0
- universal_mcp/applications/semrush/app.py +2081 -0
- universal_mcp/applications/sendgrid/README.md +362 -0
- universal_mcp/applications/sendgrid/__init__.py +1 -0
- universal_mcp/applications/sendgrid/app.py +9752 -0
- universal_mcp/applications/sentry/README.md +186 -0
- universal_mcp/applications/sentry/__init__.py +1 -0
- universal_mcp/applications/sentry/app.py +7471 -0
- universal_mcp/applications/serpapi/README.md +14 -0
- universal_mcp/applications/serpapi/__init__.py +1 -0
- universal_mcp/applications/serpapi/app.py +293 -0
- universal_mcp/applications/sharepoint/README.md +0 -0
- universal_mcp/applications/sharepoint/__init__.py +1 -0
- universal_mcp/applications/sharepoint/app.py +215 -0
- universal_mcp/applications/shopify/README.md +321 -0
- universal_mcp/applications/shopify/__init__.py +1 -0
- universal_mcp/applications/shopify/app.py +15392 -0
- universal_mcp/applications/shortcut/README.md +128 -0
- universal_mcp/applications/shortcut/__init__.py +1 -0
- universal_mcp/applications/shortcut/app.py +4478 -0
- universal_mcp/applications/slack/README.md +0 -0
- universal_mcp/applications/slack/__init__.py +1 -0
- universal_mcp/applications/slack/app.py +570 -0
- universal_mcp/applications/spotify/README.md +91 -0
- universal_mcp/applications/spotify/__init__.py +1 -0
- universal_mcp/applications/spotify/app.py +2526 -0
- universal_mcp/applications/supabase/README.md +87 -0
- universal_mcp/applications/supabase/__init__.py +1 -0
- universal_mcp/applications/supabase/app.py +2970 -0
- universal_mcp/applications/tavily/README.md +12 -0
- universal_mcp/applications/tavily/__init__.py +1 -0
- universal_mcp/applications/tavily/app.py +51 -0
- universal_mcp/applications/trello/README.md +266 -0
- universal_mcp/applications/trello/__init__.py +1 -0
- universal_mcp/applications/trello/app.py +10875 -0
- universal_mcp/applications/twillo/README.md +0 -0
- universal_mcp/applications/twillo/__init__.py +1 -0
- universal_mcp/applications/twillo/app.py +269 -0
- universal_mcp/applications/twitter/README.md +100 -0
- universal_mcp/applications/twitter/__init__.py +1 -0
- universal_mcp/applications/twitter/api_segments/__init__.py +0 -0
- universal_mcp/applications/twitter/api_segments/api_segment_base.py +51 -0
- universal_mcp/applications/twitter/api_segments/compliance_api.py +122 -0
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +255 -0
- universal_mcp/applications/twitter/api_segments/dm_events_api.py +140 -0
- universal_mcp/applications/twitter/api_segments/likes_api.py +159 -0
- universal_mcp/applications/twitter/api_segments/lists_api.py +395 -0
- universal_mcp/applications/twitter/api_segments/openapi_json_api.py +34 -0
- universal_mcp/applications/twitter/api_segments/spaces_api.py +309 -0
- universal_mcp/applications/twitter/api_segments/trends_api.py +40 -0
- universal_mcp/applications/twitter/api_segments/tweets_api.py +1403 -0
- universal_mcp/applications/twitter/api_segments/usage_api.py +40 -0
- universal_mcp/applications/twitter/api_segments/users_api.py +1498 -0
- universal_mcp/applications/twitter/app.py +46 -0
- universal_mcp/applications/unipile/README.md +28 -0
- universal_mcp/applications/unipile/__init__.py +1 -0
- universal_mcp/applications/unipile/app.py +829 -0
- universal_mcp/applications/whatsapp/README.md +23 -0
- universal_mcp/applications/whatsapp/__init__.py +1 -0
- universal_mcp/applications/whatsapp/app.py +595 -0
- universal_mcp/applications/whatsapp-business/README.md +34 -0
- universal_mcp/applications/whatsapp-business/__init__.py +1 -0
- universal_mcp/applications/whatsapp-business/app.py +1065 -0
- universal_mcp/applications/wrike/README.md +46 -0
- universal_mcp/applications/wrike/__init__.py +1 -0
- universal_mcp/applications/wrike/app.py +1583 -0
- universal_mcp/applications/youtube/README.md +57 -0
- universal_mcp/applications/youtube/__init__.py +1 -0
- universal_mcp/applications/youtube/app.py +1696 -0
- universal_mcp/applications/zenquotes/README.md +12 -0
- universal_mcp/applications/zenquotes/__init__.py +1 -0
- universal_mcp/applications/zenquotes/app.py +31 -0
- universal_mcp_applications-0.1.1.dist-info/METADATA +172 -0
- universal_mcp_applications-0.1.1.dist-info/RECORD +268 -0
- universal_mcp_applications-0.1.1.dist-info/WHEEL +4 -0
- universal_mcp_applications-0.1.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,1941 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from universal_mcp.applications.application import APIApplication
|
|
4
|
+
from universal_mcp.integrations import Integration
|
|
5
|
+
from universal_mcp_google_sheet.helper import (
|
|
6
|
+
analyze_sheet_for_tables,
|
|
7
|
+
analyze_table_schema,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GoogleSheetApp(APIApplication):
|
|
12
|
+
"""
|
|
13
|
+
Application for interacting with Google Sheets API.
|
|
14
|
+
Provides tools to create and manage Google Spreadsheets.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, integration: Integration | None = None) -> None:
|
|
18
|
+
super().__init__(name="google-sheet", integration=integration)
|
|
19
|
+
self.base_url = "https://sheets.googleapis.com/v4/spreadsheets"
|
|
20
|
+
|
|
21
|
+
def create_spreadsheet(self, title: str) -> dict[str, Any]:
|
|
22
|
+
"""
|
|
23
|
+
Creates a new blank Google Spreadsheet with the specified title and returns the API response.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
title: String representing the desired title for the new spreadsheet
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Dictionary containing the full response from the Google Sheets API, including the spreadsheet's metadata and properties
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
HTTPError: When the API request fails due to invalid authentication, network issues, or API limitations
|
|
33
|
+
ValueError: When the title parameter is empty or contains invalid characters
|
|
34
|
+
|
|
35
|
+
Tags:
|
|
36
|
+
create, spreadsheet, google-sheets, api, important
|
|
37
|
+
"""
|
|
38
|
+
url = self.base_url
|
|
39
|
+
spreadsheet_data = {"properties": {"title": title}}
|
|
40
|
+
response = self._post(url, data=spreadsheet_data)
|
|
41
|
+
return self._handle_response(response)
|
|
42
|
+
|
|
43
|
+
def get_spreadsheet(self, spreadsheet_id: str) -> dict[str, Any]:
|
|
44
|
+
"""
|
|
45
|
+
Retrieves detailed information about a specific Google Spreadsheet using its ID excluding cell data.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to retrieve (found in the spreadsheet's URL)
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
A dictionary containing the full spreadsheet metadata and contents, including properties, sheets, named ranges, and other spreadsheet-specific information from the Google Sheets API
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
HTTPError: When the API request fails due to invalid spreadsheet_id or insufficient permissions
|
|
55
|
+
ConnectionError: When there's a network connectivity issue
|
|
56
|
+
ValueError: When the response cannot be parsed as JSON
|
|
57
|
+
|
|
58
|
+
Tags:
|
|
59
|
+
get, retrieve, spreadsheet, api, metadata, read, important
|
|
60
|
+
"""
|
|
61
|
+
url = f"{self.base_url}/{spreadsheet_id}"
|
|
62
|
+
response = self._get(url)
|
|
63
|
+
return self._handle_response(response)
|
|
64
|
+
|
|
65
|
+
def get_values(
|
|
66
|
+
self,
|
|
67
|
+
spreadsheetId: str,
|
|
68
|
+
range: str,
|
|
69
|
+
majorDimension: str | None = None,
|
|
70
|
+
valueRenderOption: str | None = None,
|
|
71
|
+
dateTimeRenderOption: str | None = None,
|
|
72
|
+
) -> dict[str, Any]:
|
|
73
|
+
"""
|
|
74
|
+
Retrieves values from a specific range in a Google Spreadsheet.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
spreadsheetId: The unique identifier of the Google Spreadsheet to retrieve values from
|
|
78
|
+
range: A1 notation range string (e.g., 'Sheet1!A1:B2')
|
|
79
|
+
majorDimension: The major dimension that results should use. "ROWS" or "COLUMNS". Example: "ROWS"
|
|
80
|
+
valueRenderOption: How values should be represented in the output. "FORMATTED_VALUE", "UNFORMATTED_VALUE", or "FORMULA". Example: "FORMATTED_VALUE"
|
|
81
|
+
dateTimeRenderOption: How dates, times, and durations should be represented. "SERIAL_NUMBER" or "FORMATTED_STRING". Example: "FORMATTED_STRING"
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
A dictionary containing the API response with the requested spreadsheet values and metadata
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
HTTPError: If the API request fails due to invalid spreadsheet_id, insufficient permissions, or invalid range format
|
|
88
|
+
ValueError: If the spreadsheet_id is empty or invalid
|
|
89
|
+
|
|
90
|
+
Tags:
|
|
91
|
+
get, read, spreadsheet, values, important
|
|
92
|
+
"""
|
|
93
|
+
url = f"{self.base_url}/{spreadsheetId}/values/{range}"
|
|
94
|
+
params = {}
|
|
95
|
+
|
|
96
|
+
if majorDimension:
|
|
97
|
+
params["majorDimension"] = majorDimension
|
|
98
|
+
if valueRenderOption:
|
|
99
|
+
params["valueRenderOption"] = valueRenderOption
|
|
100
|
+
if dateTimeRenderOption:
|
|
101
|
+
params["dateTimeRenderOption"] = dateTimeRenderOption
|
|
102
|
+
|
|
103
|
+
response = self._get(url, params=params)
|
|
104
|
+
return self._handle_response(response)
|
|
105
|
+
|
|
106
|
+
def batch_get_values(
|
|
107
|
+
self, spreadsheet_id: str, ranges: list[str] | None = None
|
|
108
|
+
) -> dict[str, Any]:
|
|
109
|
+
"""
|
|
110
|
+
Retrieves multiple ranges of values from a Google Spreadsheet in a single batch request.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to retrieve values from
|
|
114
|
+
ranges: Optional list of A1 notation or R1C1 notation range strings (e.g., ['Sheet1!A1:B2', 'Sheet2!C3:D4']). If None, returns values from the entire spreadsheet
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
A dictionary containing the API response with the requested spreadsheet values and metadata
|
|
118
|
+
|
|
119
|
+
Raises:
|
|
120
|
+
HTTPError: If the API request fails due to invalid spreadsheet_id, insufficient permissions, or invalid range format
|
|
121
|
+
ValueError: If the spreadsheet_id is empty or invalid
|
|
122
|
+
|
|
123
|
+
Tags:
|
|
124
|
+
get, batch, read, spreadsheet, values
|
|
125
|
+
"""
|
|
126
|
+
url = f"{self.base_url}/{spreadsheet_id}/values:batchGet"
|
|
127
|
+
params = {}
|
|
128
|
+
if ranges:
|
|
129
|
+
params["ranges"] = ranges
|
|
130
|
+
response = self._get(url, params=params)
|
|
131
|
+
return self._handle_response(response)
|
|
132
|
+
|
|
133
|
+
def insert_dimensions(
|
|
134
|
+
self,
|
|
135
|
+
spreadsheet_id: str,
|
|
136
|
+
sheet_id: int,
|
|
137
|
+
dimension: str,
|
|
138
|
+
start_index: int,
|
|
139
|
+
end_index: int,
|
|
140
|
+
inherit_from_before: bool = True,
|
|
141
|
+
include_spreadsheet_in_response: bool | None = None,
|
|
142
|
+
response_include_grid_data: bool | None = None,
|
|
143
|
+
response_ranges: list[str] | None = None,
|
|
144
|
+
) -> dict[str, Any]:
|
|
145
|
+
"""
|
|
146
|
+
Inserts new rows or columns into a Google Sheet at a specific position within the sheet.
|
|
147
|
+
|
|
148
|
+
This function inserts empty rows or columns at a specified location, shifting existing content.
|
|
149
|
+
Use this when you need to add rows/columns in the middle of your data.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
spreadsheet_id: The ID of the spreadsheet to update. Example: "abc123spreadsheetId"
|
|
153
|
+
sheet_id: The ID of the sheet where the dimensions will be inserted. Example: 0
|
|
154
|
+
dimension: The dimension to insert. Valid values are "ROWS" or "COLUMNS". Example: "ROWS"
|
|
155
|
+
start_index: The start index (0-based) of the dimension range to insert. The inserted dimensions will be placed before this index. Example: 1
|
|
156
|
+
end_index: The end index (0-based, exclusive) of the dimension range to insert. The number of rows/columns to insert is `endIndex - startIndex`. Example: 3
|
|
157
|
+
inherit_from_before: If true, the new dimensions will inherit properties from the dimension before the startIndex. If false (default), they will inherit from the dimension at the startIndex. startIndex must be greater than 0 if inheritFromBefore is true. Example: True
|
|
158
|
+
include_spreadsheet_in_response: True if the updated spreadsheet should be included in the response. Example: True
|
|
159
|
+
response_include_grid_data: True if grid data should be included in the response (if includeSpreadsheetInResponse is true). Example: True
|
|
160
|
+
response_ranges: Limits the ranges of the spreadsheet to include in the response. Example: ["Sheet1!A1:B10"]
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
A dictionary containing the Google Sheets API response with update details
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
167
|
+
ValueError: When spreadsheet_id is empty or dimension is not "ROWS" or "COLUMNS"
|
|
168
|
+
|
|
169
|
+
Tags:
|
|
170
|
+
insert, modify, spreadsheet, rows, columns, dimensions, important
|
|
171
|
+
"""
|
|
172
|
+
if not spreadsheet_id:
|
|
173
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
174
|
+
|
|
175
|
+
if dimension not in ["ROWS", "COLUMNS"]:
|
|
176
|
+
raise ValueError('dimension must be either "ROWS" or "COLUMNS"')
|
|
177
|
+
|
|
178
|
+
if start_index < 0 or end_index < 0:
|
|
179
|
+
raise ValueError("start_index and end_index must be non-negative")
|
|
180
|
+
|
|
181
|
+
if start_index >= end_index:
|
|
182
|
+
raise ValueError("end_index must be greater than start_index")
|
|
183
|
+
|
|
184
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
185
|
+
|
|
186
|
+
request_body: dict[str, Any] = {
|
|
187
|
+
"requests": [
|
|
188
|
+
{
|
|
189
|
+
"insertDimension": {
|
|
190
|
+
"inheritFromBefore": inherit_from_before,
|
|
191
|
+
"range": {
|
|
192
|
+
"dimension": dimension,
|
|
193
|
+
"sheetId": sheet_id,
|
|
194
|
+
"startIndex": start_index,
|
|
195
|
+
"endIndex": end_index,
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
# Add optional parameters if provided
|
|
203
|
+
if include_spreadsheet_in_response is not None:
|
|
204
|
+
request_body["includeSpreadsheetInResponse"] = (
|
|
205
|
+
include_spreadsheet_in_response
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if response_include_grid_data is not None:
|
|
209
|
+
request_body["responseIncludeGridData"] = response_include_grid_data
|
|
210
|
+
|
|
211
|
+
if response_ranges is not None:
|
|
212
|
+
request_body["responseRanges"] = response_ranges
|
|
213
|
+
|
|
214
|
+
response = self._post(url, data=request_body)
|
|
215
|
+
return self._handle_response(response)
|
|
216
|
+
|
|
217
|
+
def append_dimensions(
|
|
218
|
+
self,
|
|
219
|
+
spreadsheet_id: str,
|
|
220
|
+
sheet_id: int,
|
|
221
|
+
dimension: str,
|
|
222
|
+
length: int,
|
|
223
|
+
) -> dict[str, Any]:
|
|
224
|
+
"""
|
|
225
|
+
Appends empty rows or columns to the end of a Google Sheet.
|
|
226
|
+
|
|
227
|
+
This function adds empty rows or columns to the end of the sheet without affecting existing content.
|
|
228
|
+
Use this when you need to extend the sheet with additional space at the bottom or right.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to modify
|
|
232
|
+
sheet_id: The ID of the sheet within the spreadsheet (0 for first sheet)
|
|
233
|
+
dimension: The type of dimension to append - "ROWS" or "COLUMNS"
|
|
234
|
+
length: The number of rows or columns to append to the end
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
A dictionary containing the Google Sheets API response with update details
|
|
238
|
+
|
|
239
|
+
Raises:
|
|
240
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
241
|
+
ValueError: When spreadsheet_id is empty, dimension is not "ROWS" or "COLUMNS", or length is not positive
|
|
242
|
+
|
|
243
|
+
Tags:
|
|
244
|
+
append, modify, spreadsheet, rows, columns, dimensions, important
|
|
245
|
+
"""
|
|
246
|
+
if not spreadsheet_id:
|
|
247
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
248
|
+
|
|
249
|
+
if dimension not in ["ROWS", "COLUMNS"]:
|
|
250
|
+
raise ValueError('dimension must be either "ROWS" or "COLUMNS"')
|
|
251
|
+
|
|
252
|
+
if length <= 0:
|
|
253
|
+
raise ValueError("length must be a positive integer")
|
|
254
|
+
|
|
255
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
256
|
+
|
|
257
|
+
request_body = {
|
|
258
|
+
"requests": [
|
|
259
|
+
{
|
|
260
|
+
"appendDimension": {
|
|
261
|
+
"sheetId": sheet_id,
|
|
262
|
+
"dimension": dimension,
|
|
263
|
+
"length": length,
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
response = self._post(url, data=request_body)
|
|
270
|
+
return self._handle_response(response)
|
|
271
|
+
|
|
272
|
+
def delete_dimensions(
|
|
273
|
+
self,
|
|
274
|
+
spreadsheet_id: str,
|
|
275
|
+
sheet_id: int,
|
|
276
|
+
dimension: str,
|
|
277
|
+
start_index: int,
|
|
278
|
+
end_index: int,
|
|
279
|
+
include_spreadsheet_in_response: bool | None = None,
|
|
280
|
+
response_include_grid_data: bool | None = None,
|
|
281
|
+
response_ranges: list[str] | None = None,
|
|
282
|
+
) -> dict[str, Any]:
|
|
283
|
+
"""
|
|
284
|
+
Tool to delete specified rows or columns from a sheet in a google spreadsheet. use when you need to remove a range of rows or columns.
|
|
285
|
+
or Use this when you need to remove unwanted rows or columns from your data.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
spreadsheet_id: The ID of the spreadsheet. Example: "abc123xyz789"
|
|
289
|
+
sheet_id: The ID of the sheet from which to delete the dimension. Example: 0 for first sheet
|
|
290
|
+
dimension: The dimension to delete. Example: "ROWS"
|
|
291
|
+
start_index: The zero-based start index of the range to delete, inclusive. The start index must be less than the end index. Example: 0
|
|
292
|
+
end_index: The zero-based end index of the range to delete, exclusive. The end index must be greater than the start index. Example: 1
|
|
293
|
+
include_spreadsheet_in_response: Determines if the update response should include the spreadsheet resource. Example: True
|
|
294
|
+
response_include_grid_data: True if grid data should be returned. This parameter is ignored if a field mask was set in the request. Example: True
|
|
295
|
+
response_ranges: Limits the ranges of cells included in the response spreadsheet. Example: ["Sheet1!A1:B2", "Sheet2!C:C"]
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
A dictionary containing the Google Sheets API response with update details
|
|
299
|
+
|
|
300
|
+
Raises:
|
|
301
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
302
|
+
ValueError: When spreadsheet_id is empty, dimension is not "ROWS" or "COLUMNS", or indices are invalid
|
|
303
|
+
|
|
304
|
+
Tags:
|
|
305
|
+
delete, modify, spreadsheet, rows, columns, dimensions, important
|
|
306
|
+
"""
|
|
307
|
+
if not spreadsheet_id:
|
|
308
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
309
|
+
|
|
310
|
+
if dimension not in ["ROWS", "COLUMNS"]:
|
|
311
|
+
raise ValueError('dimension must be either "ROWS" or "COLUMNS"')
|
|
312
|
+
|
|
313
|
+
if start_index < 0 or end_index < 0:
|
|
314
|
+
raise ValueError("start_index and end_index must be non-negative")
|
|
315
|
+
|
|
316
|
+
if start_index >= end_index:
|
|
317
|
+
raise ValueError("end_index must be greater than start_index")
|
|
318
|
+
|
|
319
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
320
|
+
|
|
321
|
+
request_body: dict[str, Any] = {
|
|
322
|
+
"requests": [
|
|
323
|
+
{
|
|
324
|
+
"deleteDimension": {
|
|
325
|
+
"range": {
|
|
326
|
+
"sheetId": sheet_id,
|
|
327
|
+
"dimension": dimension,
|
|
328
|
+
"startIndex": start_index,
|
|
329
|
+
"endIndex": end_index,
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
# Add optional response parameters if provided
|
|
337
|
+
if include_spreadsheet_in_response is not None:
|
|
338
|
+
request_body["includeSpreadsheetInResponse"] = (
|
|
339
|
+
include_spreadsheet_in_response
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
if response_include_grid_data is not None:
|
|
343
|
+
request_body["responseIncludeGridData"] = response_include_grid_data
|
|
344
|
+
|
|
345
|
+
if response_ranges is not None:
|
|
346
|
+
request_body["responseRanges"] = response_ranges
|
|
347
|
+
|
|
348
|
+
response = self._post(url, data=request_body)
|
|
349
|
+
return self._handle_response(response)
|
|
350
|
+
|
|
351
|
+
def add_sheet(
|
|
352
|
+
self,
|
|
353
|
+
spreadsheetId: str,
|
|
354
|
+
title: str | None = None,
|
|
355
|
+
sheetId: int | None = None,
|
|
356
|
+
index: int | None = None,
|
|
357
|
+
sheetType: str = "GRID",
|
|
358
|
+
hidden: bool | None = None,
|
|
359
|
+
rightToLeft: bool | None = None,
|
|
360
|
+
tabColorStyle: dict | None = None,
|
|
361
|
+
# Grid properties
|
|
362
|
+
rowCount: int | None = None,
|
|
363
|
+
columnCount: int | None = None,
|
|
364
|
+
frozenRowCount: int | None = None,
|
|
365
|
+
frozenColumnCount: int | None = None,
|
|
366
|
+
hideGridlines: bool | None = None,
|
|
367
|
+
rowGroupControlAfter: bool | None = None,
|
|
368
|
+
columnGroupControlAfter: bool | None = None,
|
|
369
|
+
# Response options
|
|
370
|
+
includeSpreadsheetInResponse: bool = False,
|
|
371
|
+
responseIncludeGridData: bool = False,
|
|
372
|
+
) -> dict[str, Any]:
|
|
373
|
+
"""
|
|
374
|
+
Adds a new sheet (worksheet) to a spreadsheet. use this tool to create a new tab within an existing google sheet, optionally specifying its title, index, size, and other properties.
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
spreadsheetId: The ID of the spreadsheet to add the sheet to. This is the long string of characters in the URL of your Google Sheet. Example: "abc123xyz789"
|
|
378
|
+
title: The name of the sheet. Example: "Q3 Report"
|
|
379
|
+
sheetId: The ID of the sheet. If not set, an ID will be randomly generated. Must be non-negative if set.
|
|
380
|
+
index: The zero-based index of the sheet in the spreadsheet. Example: 0 for the first sheet.
|
|
381
|
+
sheetType: The type of sheet. Options: "GRID", "OBJECT", "DATA_SOURCE". Defaults to "GRID"
|
|
382
|
+
hidden: True if the sheet is hidden in the UI, false if it's visible.
|
|
383
|
+
rightToLeft: True if the sheet is an RTL sheet, false if it's LTR.
|
|
384
|
+
tabColorStyle: The color of the sheet tab. Can contain either 'rgbColor' (with red, green, blue, alpha values 0-1) or 'themeColor' (TEXT, BACKGROUND, ACCENT1-6, LINK).
|
|
385
|
+
rowCount: The number of rows in the sheet.
|
|
386
|
+
columnCount: The number of columns in the sheet.
|
|
387
|
+
frozenRowCount: The number of rows that are frozen in the sheet.
|
|
388
|
+
frozenColumnCount: The number of columns that are frozen in the sheet.
|
|
389
|
+
hideGridlines: True if the gridlines are hidden, false if they are shown.
|
|
390
|
+
rowGroupControlAfter: True if the row group control toggle is shown after the group, false if before.
|
|
391
|
+
columnGroupControlAfter: True if the column group control toggle is shown after the group, false if before.
|
|
392
|
+
includeSpreadsheetInResponse: Whether the response should include the entire spreadsheet resource. Defaults to false.
|
|
393
|
+
responseIncludeGridData: True if grid data should be returned. This parameter is ignored if includeSpreadsheetInResponse is false. Defaults to false.
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
A dictionary containing the Google Sheets API response with the new sheet details
|
|
397
|
+
|
|
398
|
+
Raises:
|
|
399
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
400
|
+
ValueError: When spreadsheet_id is empty or invalid parameters are provided
|
|
401
|
+
|
|
402
|
+
Tags:
|
|
403
|
+
add, sheet, spreadsheet, create
|
|
404
|
+
"""
|
|
405
|
+
if not spreadsheetId:
|
|
406
|
+
raise ValueError("spreadsheetId cannot be empty")
|
|
407
|
+
|
|
408
|
+
url = f"{self.base_url}/{spreadsheetId}:batchUpdate"
|
|
409
|
+
|
|
410
|
+
# Build the addSheet request with properties
|
|
411
|
+
add_sheet_request = {"properties": {}}
|
|
412
|
+
|
|
413
|
+
if title is not None:
|
|
414
|
+
add_sheet_request["properties"]["title"] = title
|
|
415
|
+
|
|
416
|
+
if sheetId is not None:
|
|
417
|
+
add_sheet_request["properties"]["sheetId"] = sheetId
|
|
418
|
+
|
|
419
|
+
if index is not None:
|
|
420
|
+
add_sheet_request["properties"]["index"] = index
|
|
421
|
+
|
|
422
|
+
if sheetType is not None:
|
|
423
|
+
add_sheet_request["properties"]["sheetType"] = sheetType
|
|
424
|
+
|
|
425
|
+
if hidden is not None:
|
|
426
|
+
add_sheet_request["properties"]["hidden"] = hidden
|
|
427
|
+
|
|
428
|
+
if rightToLeft is not None:
|
|
429
|
+
add_sheet_request["properties"]["rightToLeft"] = rightToLeft
|
|
430
|
+
|
|
431
|
+
if tabColorStyle is not None:
|
|
432
|
+
add_sheet_request["properties"]["tabColorStyle"] = tabColorStyle
|
|
433
|
+
|
|
434
|
+
# Build grid properties if any grid-related parameters are provided
|
|
435
|
+
grid_properties = {}
|
|
436
|
+
if any(
|
|
437
|
+
param is not None
|
|
438
|
+
for param in [
|
|
439
|
+
rowCount,
|
|
440
|
+
columnCount,
|
|
441
|
+
frozenRowCount,
|
|
442
|
+
frozenColumnCount,
|
|
443
|
+
hideGridlines,
|
|
444
|
+
rowGroupControlAfter,
|
|
445
|
+
columnGroupControlAfter,
|
|
446
|
+
]
|
|
447
|
+
):
|
|
448
|
+
if rowCount is not None:
|
|
449
|
+
grid_properties["rowCount"] = rowCount
|
|
450
|
+
|
|
451
|
+
if columnCount is not None:
|
|
452
|
+
grid_properties["columnCount"] = columnCount
|
|
453
|
+
|
|
454
|
+
if frozenRowCount is not None:
|
|
455
|
+
grid_properties["frozenRowCount"] = frozenRowCount
|
|
456
|
+
|
|
457
|
+
if frozenColumnCount is not None:
|
|
458
|
+
grid_properties["frozenColumnCount"] = frozenColumnCount
|
|
459
|
+
|
|
460
|
+
if hideGridlines is not None:
|
|
461
|
+
grid_properties["hideGridlines"] = hideGridlines
|
|
462
|
+
|
|
463
|
+
if rowGroupControlAfter is not None:
|
|
464
|
+
grid_properties["rowGroupControlAfter"] = rowGroupControlAfter
|
|
465
|
+
|
|
466
|
+
if columnGroupControlAfter is not None:
|
|
467
|
+
grid_properties["columnGroupControlAfter"] = columnGroupControlAfter
|
|
468
|
+
|
|
469
|
+
add_sheet_request["properties"]["gridProperties"] = grid_properties
|
|
470
|
+
|
|
471
|
+
request_body = {
|
|
472
|
+
"requests": [{"addSheet": add_sheet_request}],
|
|
473
|
+
"includeSpreadsheetInResponse": includeSpreadsheetInResponse,
|
|
474
|
+
"responseIncludeGridData": responseIncludeGridData,
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
response = self._post(url, data=request_body)
|
|
478
|
+
return self._handle_response(response)
|
|
479
|
+
|
|
480
|
+
def add_basic_chart(
|
|
481
|
+
self,
|
|
482
|
+
spreadsheet_id: str,
|
|
483
|
+
source_sheet_id: int,
|
|
484
|
+
chart_title: str,
|
|
485
|
+
chart_type: str,
|
|
486
|
+
domain_range: dict,
|
|
487
|
+
series_ranges: list[dict],
|
|
488
|
+
new_sheet: bool = False,
|
|
489
|
+
chart_position: dict | None = None,
|
|
490
|
+
x_axis_title: str | None = None,
|
|
491
|
+
y_axis_title: str | None = None,
|
|
492
|
+
) -> dict[str, Any]:
|
|
493
|
+
"""
|
|
494
|
+
Adds a basic chart to a Google Spreadsheet like a column chart, bar chart, line chart and area chart.
|
|
495
|
+
|
|
496
|
+
This function creates various types of charts from the specified data ranges and places it in a new sheet or existing sheet.
|
|
497
|
+
Use this when you need to visualize data in different chart formats.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to modify
|
|
501
|
+
source_sheet_id: The ID of the sheet containing the source data
|
|
502
|
+
chart_title: The title for the chart
|
|
503
|
+
chart_type: The type of chart to create. Supported types: "COLUMN", "BAR", "LINE", "AREA", "STEPPED_AREA", "SCATTER", "COMBO"
|
|
504
|
+
domain_range: Dictionary containing domain range info (e.g., {"startRowIndex": 0, "endRowIndex": 7, "startColumnIndex": 0, "endColumnIndex": 1})
|
|
505
|
+
series_ranges: List of dictionaries containing series range info for each data series
|
|
506
|
+
new_sheet: Whether to create the chart in a new sheet (True) or existing sheet (False)
|
|
507
|
+
chart_position: Optional positioning for chart when new_sheet=False. Example: {"overlayPosition": {"anchorCell": {"sheetId": 0, "rowIndex": 10, "columnIndex": 5}, "offsetXPixels": 0, "offsetYPixels": 0, "widthPixels": 600, "heightPixels": 400}}
|
|
508
|
+
x_axis_title: Optional title for the X-axis (bottom axis). If not provided, defaults to "Categories"
|
|
509
|
+
y_axis_title: Optional title for the Y-axis (left axis). If not provided, defaults to "Values"
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
A dictionary containing the Google Sheets API response with the chart details
|
|
513
|
+
|
|
514
|
+
Raises:
|
|
515
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
516
|
+
ValueError: When spreadsheet_id is empty or invalid parameters are provided
|
|
517
|
+
|
|
518
|
+
Tags:
|
|
519
|
+
add, chart, basic-chart, visualization
|
|
520
|
+
"""
|
|
521
|
+
if not spreadsheet_id:
|
|
522
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
523
|
+
|
|
524
|
+
if not chart_title:
|
|
525
|
+
raise ValueError("chart_title cannot be empty")
|
|
526
|
+
|
|
527
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
528
|
+
|
|
529
|
+
# Build the chart specification
|
|
530
|
+
chart_spec = {
|
|
531
|
+
"title": chart_title,
|
|
532
|
+
"basicChart": {
|
|
533
|
+
"chartType": chart_type,
|
|
534
|
+
"legendPosition": "BOTTOM_LEGEND",
|
|
535
|
+
"axis": [
|
|
536
|
+
{
|
|
537
|
+
"position": "BOTTOM_AXIS",
|
|
538
|
+
"title": x_axis_title if x_axis_title else "Categories",
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
"position": "LEFT_AXIS",
|
|
542
|
+
"title": y_axis_title if y_axis_title else "Values",
|
|
543
|
+
},
|
|
544
|
+
],
|
|
545
|
+
"domains": [
|
|
546
|
+
{
|
|
547
|
+
"domain": {
|
|
548
|
+
"sourceRange": {
|
|
549
|
+
"sources": [
|
|
550
|
+
{
|
|
551
|
+
"sheetId": source_sheet_id,
|
|
552
|
+
"startRowIndex": domain_range.get(
|
|
553
|
+
"startRowIndex", 0
|
|
554
|
+
),
|
|
555
|
+
"endRowIndex": domain_range.get(
|
|
556
|
+
"endRowIndex", 1
|
|
557
|
+
),
|
|
558
|
+
"startColumnIndex": domain_range.get(
|
|
559
|
+
"startColumnIndex", 0
|
|
560
|
+
),
|
|
561
|
+
"endColumnIndex": domain_range.get(
|
|
562
|
+
"endColumnIndex", 1
|
|
563
|
+
),
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
],
|
|
570
|
+
"series": [],
|
|
571
|
+
"headerCount": 1,
|
|
572
|
+
},
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
# Add series data
|
|
576
|
+
for series_range in series_ranges:
|
|
577
|
+
series = {
|
|
578
|
+
"series": {
|
|
579
|
+
"sourceRange": {
|
|
580
|
+
"sources": [
|
|
581
|
+
{
|
|
582
|
+
"sheetId": source_sheet_id,
|
|
583
|
+
"startRowIndex": series_range.get("startRowIndex", 0),
|
|
584
|
+
"endRowIndex": series_range.get("endRowIndex", 1),
|
|
585
|
+
"startColumnIndex": series_range.get(
|
|
586
|
+
"startColumnIndex", 0
|
|
587
|
+
),
|
|
588
|
+
"endColumnIndex": series_range.get("endColumnIndex", 1),
|
|
589
|
+
}
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
"targetAxis": "LEFT_AXIS",
|
|
594
|
+
}
|
|
595
|
+
chart_spec["basicChart"]["series"].append(series)
|
|
596
|
+
|
|
597
|
+
# Build the position specification
|
|
598
|
+
if new_sheet:
|
|
599
|
+
position_spec = {"newSheet": True}
|
|
600
|
+
# For existing sheet, use overlayPosition structure
|
|
601
|
+
elif chart_position:
|
|
602
|
+
position_spec = chart_position
|
|
603
|
+
else:
|
|
604
|
+
# Default positioning when placing in existing sheet
|
|
605
|
+
position_spec = {
|
|
606
|
+
"overlayPosition": {
|
|
607
|
+
"anchorCell": {
|
|
608
|
+
"sheetId": source_sheet_id,
|
|
609
|
+
"rowIndex": 0,
|
|
610
|
+
"columnIndex": 0,
|
|
611
|
+
},
|
|
612
|
+
"offsetXPixels": 0,
|
|
613
|
+
"offsetYPixels": 0,
|
|
614
|
+
"widthPixels": 600,
|
|
615
|
+
"heightPixels": 400,
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
# Build the request body
|
|
620
|
+
request_body = {
|
|
621
|
+
"requests": [
|
|
622
|
+
{"addChart": {"chart": {"spec": chart_spec, "position": position_spec}}}
|
|
623
|
+
]
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
response = self._post(url, data=request_body)
|
|
627
|
+
return self._handle_response(response)
|
|
628
|
+
|
|
629
|
+
def add_pie_chart(
|
|
630
|
+
self,
|
|
631
|
+
spreadsheet_id: str,
|
|
632
|
+
source_sheet_id: int,
|
|
633
|
+
chart_title: str,
|
|
634
|
+
data_range: dict,
|
|
635
|
+
new_sheet: bool = False,
|
|
636
|
+
chart_position: dict | None = None,
|
|
637
|
+
legend_position: str = "BOTTOM_LEGEND",
|
|
638
|
+
pie_hole: float | None = None,
|
|
639
|
+
) -> dict[str, Any]:
|
|
640
|
+
"""
|
|
641
|
+
Adds a pie chart to a Google Spreadsheet.
|
|
642
|
+
|
|
643
|
+
This function creates a pie chart from the specified data range and places it in a new sheet or existing sheet.
|
|
644
|
+
Use this when you need to visualize data as proportions of a whole.
|
|
645
|
+
|
|
646
|
+
Args:
|
|
647
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to modify
|
|
648
|
+
source_sheet_id: The ID of the sheet containing the source data
|
|
649
|
+
chart_title: The title for the chart
|
|
650
|
+
data_range: Dictionary containing data range info (e.g., {"startRowIndex": 0, "endRowIndex": 7, "startColumnIndex": 0, "endColumnIndex": 2})
|
|
651
|
+
new_sheet: Whether to create the chart in a new sheet (True) or existing sheet (False)
|
|
652
|
+
chart_position: Optional positioning for chart when new_sheet=False. Example: {"overlayPosition": {"anchorCell": {"sheetId": 0, "rowIndex": 10, "columnIndex": 5}, "offsetXPixels": 0, "offsetYPixels": 0, "widthPixels": 600, "heightPixels": 400}}
|
|
653
|
+
legend_position: Position of the legend. Options: "BOTTOM_LEGEND", "LEFT_LEGEND", "RIGHT_LEGEND", "TOP_LEGEND", "NO_LEGEND"
|
|
654
|
+
pie_hole: Optional hole size for creating a donut chart (0.0 to 1.0). 0.0 = solid pie, 0.5 = 50% hole
|
|
655
|
+
|
|
656
|
+
Returns:
|
|
657
|
+
A dictionary containing the Google Sheets API response with the chart details
|
|
658
|
+
|
|
659
|
+
Raises:
|
|
660
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
661
|
+
ValueError: When spreadsheet_id is empty or invalid parameters are provided
|
|
662
|
+
|
|
663
|
+
Tags:
|
|
664
|
+
add, chart, pie, visualization
|
|
665
|
+
"""
|
|
666
|
+
if not spreadsheet_id:
|
|
667
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
668
|
+
|
|
669
|
+
if not chart_title:
|
|
670
|
+
raise ValueError("chart_title cannot be empty")
|
|
671
|
+
|
|
672
|
+
if pie_hole is not None and not 0 <= pie_hole <= 1:
|
|
673
|
+
raise ValueError("pie_hole must be between 0.0 and 1.0")
|
|
674
|
+
|
|
675
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
676
|
+
|
|
677
|
+
# Build the pie chart specification
|
|
678
|
+
pie_chart_spec = {
|
|
679
|
+
"legendPosition": legend_position,
|
|
680
|
+
"domain": {
|
|
681
|
+
"sourceRange": {
|
|
682
|
+
"sources": [
|
|
683
|
+
{
|
|
684
|
+
"sheetId": source_sheet_id,
|
|
685
|
+
"startRowIndex": data_range.get("startRowIndex", 0),
|
|
686
|
+
"endRowIndex": data_range.get("endRowIndex", 1),
|
|
687
|
+
"startColumnIndex": data_range.get("startColumnIndex", 0),
|
|
688
|
+
"endColumnIndex": data_range.get("startColumnIndex", 0) + 1,
|
|
689
|
+
}
|
|
690
|
+
]
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
"series": {
|
|
694
|
+
"sourceRange": {
|
|
695
|
+
"sources": [
|
|
696
|
+
{
|
|
697
|
+
"sheetId": source_sheet_id,
|
|
698
|
+
"startRowIndex": data_range.get("startRowIndex", 0),
|
|
699
|
+
"endRowIndex": data_range.get("endRowIndex", 1),
|
|
700
|
+
"startColumnIndex": data_range.get("startColumnIndex", 0)
|
|
701
|
+
+ 1,
|
|
702
|
+
"endColumnIndex": data_range.get("endColumnIndex", 2),
|
|
703
|
+
}
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
# Add pie hole for donut chart if specified
|
|
710
|
+
if pie_hole is not None:
|
|
711
|
+
pie_chart_spec["pieHole"] = pie_hole
|
|
712
|
+
|
|
713
|
+
# Build the chart specification
|
|
714
|
+
chart_spec = {"title": chart_title, "pieChart": pie_chart_spec}
|
|
715
|
+
|
|
716
|
+
# Build the position specification
|
|
717
|
+
if new_sheet:
|
|
718
|
+
position_spec = {"newSheet": True}
|
|
719
|
+
# For existing sheet, use overlayPosition structure
|
|
720
|
+
elif chart_position:
|
|
721
|
+
position_spec = chart_position
|
|
722
|
+
else:
|
|
723
|
+
# Default positioning when placing in existing sheet
|
|
724
|
+
position_spec = {
|
|
725
|
+
"overlayPosition": {
|
|
726
|
+
"anchorCell": {
|
|
727
|
+
"sheetId": source_sheet_id,
|
|
728
|
+
"rowIndex": 0,
|
|
729
|
+
"columnIndex": 0,
|
|
730
|
+
},
|
|
731
|
+
"offsetXPixels": 0,
|
|
732
|
+
"offsetYPixels": 0,
|
|
733
|
+
"widthPixels": 600,
|
|
734
|
+
"heightPixels": 400,
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
# Build the request body
|
|
739
|
+
request_body = {
|
|
740
|
+
"requests": [
|
|
741
|
+
{"addChart": {"chart": {"spec": chart_spec, "position": position_spec}}}
|
|
742
|
+
]
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
response = self._post(url, data=request_body)
|
|
746
|
+
return self._handle_response(response)
|
|
747
|
+
|
|
748
|
+
def add_table(
|
|
749
|
+
self,
|
|
750
|
+
spreadsheet_id: str,
|
|
751
|
+
sheet_id: int,
|
|
752
|
+
table_name: str,
|
|
753
|
+
table_id: str,
|
|
754
|
+
start_row_index: int,
|
|
755
|
+
end_row_index: int,
|
|
756
|
+
start_column_index: int,
|
|
757
|
+
end_column_index: int,
|
|
758
|
+
column_properties: list[dict] | None = None,
|
|
759
|
+
) -> dict[str, Any]:
|
|
760
|
+
"""
|
|
761
|
+
Adds a table to a Google Spreadsheet.
|
|
762
|
+
|
|
763
|
+
This function creates a table with specified properties and column types.
|
|
764
|
+
Use this when you need to create structured data with headers, footers, and column types.
|
|
765
|
+
|
|
766
|
+
Args:
|
|
767
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to modify
|
|
768
|
+
sheet_id: The ID of the sheet where the table will be created
|
|
769
|
+
table_name: The name of the table
|
|
770
|
+
table_id: The unique identifier for the table
|
|
771
|
+
start_row_index: The starting row index (0-based)
|
|
772
|
+
end_row_index: The ending row index (exclusive)
|
|
773
|
+
start_column_index: The starting column index (0-based)
|
|
774
|
+
end_column_index: The ending column index (exclusive)
|
|
775
|
+
column_properties: Optional list of column properties with types and validation rules. Valid column types: "TEXT", "PERCENT", "DROPDOWN", "DOUBLE", "CURRENCY", "DATE", "TIME", "DATE_TIME". Example: [{"columnIndex": 0, "columnName": "Model Number", "columnType": "TEXT"}, {"columnIndex": 1, "columnName": "Sales - Jan", "columnType": "DOUBLE"}, {"columnIndex": 2, "columnName": "Price", "columnType": "CURRENCY"}, {"columnIndex": 3, "columnName": "Progress", "columnType": "PERCENT"}, {"columnIndex": 4, "columnName": "Created Date", "columnType": "DATE"}, {"columnIndex": 5, "columnName": "Status", "columnType": "DROPDOWN", "dataValidationRule": {"condition": {"type": "ONE_OF_LIST", "values": [{"userEnteredValue": "Active"}, {"userEnteredValue": "Inactive"}]}}}]
|
|
776
|
+
Returns:
|
|
777
|
+
A dictionary containing the Google Sheets API response with the table details
|
|
778
|
+
|
|
779
|
+
Raises:
|
|
780
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
781
|
+
ValueError: When spreadsheet_id is empty or invalid parameters are provided
|
|
782
|
+
|
|
783
|
+
Tags:
|
|
784
|
+
add, table, structured-data
|
|
785
|
+
"""
|
|
786
|
+
if not spreadsheet_id:
|
|
787
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
788
|
+
|
|
789
|
+
if not table_name:
|
|
790
|
+
raise ValueError("table_name cannot be empty")
|
|
791
|
+
|
|
792
|
+
if not table_id:
|
|
793
|
+
raise ValueError("table_id cannot be empty")
|
|
794
|
+
|
|
795
|
+
if (
|
|
796
|
+
start_row_index < 0
|
|
797
|
+
or end_row_index < 0
|
|
798
|
+
or start_column_index < 0
|
|
799
|
+
or end_column_index < 0
|
|
800
|
+
):
|
|
801
|
+
raise ValueError("All indices must be non-negative")
|
|
802
|
+
|
|
803
|
+
if start_row_index >= end_row_index:
|
|
804
|
+
raise ValueError("end_row_index must be greater than start_row_index")
|
|
805
|
+
|
|
806
|
+
if start_column_index >= end_column_index:
|
|
807
|
+
raise ValueError("end_column_index must be greater than start_column_index")
|
|
808
|
+
|
|
809
|
+
# Validate column properties if provided
|
|
810
|
+
if column_properties:
|
|
811
|
+
valid_column_types = [
|
|
812
|
+
"TEXT",
|
|
813
|
+
"PERCENT",
|
|
814
|
+
"DROPDOWN",
|
|
815
|
+
"DOUBLE",
|
|
816
|
+
"CURRENCY",
|
|
817
|
+
"DATE",
|
|
818
|
+
"TIME",
|
|
819
|
+
"DATE_TIME",
|
|
820
|
+
]
|
|
821
|
+
for i, prop in enumerate(column_properties):
|
|
822
|
+
if (
|
|
823
|
+
"columnType" in prop
|
|
824
|
+
and prop["columnType"] not in valid_column_types
|
|
825
|
+
):
|
|
826
|
+
raise ValueError(
|
|
827
|
+
f"Invalid column type '{prop['columnType']}' at index {i}. Valid types are: {', '.join(valid_column_types)}"
|
|
828
|
+
)
|
|
829
|
+
|
|
830
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
831
|
+
|
|
832
|
+
# Build the table specification
|
|
833
|
+
table_spec = {
|
|
834
|
+
"name": table_name,
|
|
835
|
+
"tableId": table_id,
|
|
836
|
+
"range": {
|
|
837
|
+
"sheetId": sheet_id,
|
|
838
|
+
"startColumnIndex": start_column_index,
|
|
839
|
+
"endColumnIndex": end_column_index,
|
|
840
|
+
"startRowIndex": start_row_index,
|
|
841
|
+
"endRowIndex": end_row_index,
|
|
842
|
+
},
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
# Add column properties if provided
|
|
846
|
+
if column_properties:
|
|
847
|
+
table_spec["columnProperties"] = column_properties
|
|
848
|
+
|
|
849
|
+
# Build the request body
|
|
850
|
+
request_body = {"requests": [{"addTable": {"table": table_spec}}]}
|
|
851
|
+
|
|
852
|
+
response = self._post(url, data=request_body)
|
|
853
|
+
return self._handle_response(response)
|
|
854
|
+
|
|
855
|
+
def update_table(
|
|
856
|
+
self,
|
|
857
|
+
spreadsheet_id: str,
|
|
858
|
+
table_id: str,
|
|
859
|
+
table_name: str | None = None,
|
|
860
|
+
start_row_index: int | None = None,
|
|
861
|
+
end_row_index: int | None = None,
|
|
862
|
+
start_column_index: int | None = None,
|
|
863
|
+
end_column_index: int | None = None,
|
|
864
|
+
column_properties: list[dict] | None = None,
|
|
865
|
+
) -> dict[str, Any]:
|
|
866
|
+
"""
|
|
867
|
+
Updates an existing table in a Google Spreadsheet.
|
|
868
|
+
|
|
869
|
+
This function modifies table properties such as name, range, and column properties.
|
|
870
|
+
Use this when you need to modify an existing table's structure or properties.
|
|
871
|
+
|
|
872
|
+
Args:
|
|
873
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to modify
|
|
874
|
+
table_id: The unique identifier of the table to update
|
|
875
|
+
table_name: Optional new name for the table
|
|
876
|
+
start_row_index: Optional new starting row index (0-based)
|
|
877
|
+
end_row_index: Optional new ending row index (exclusive)
|
|
878
|
+
start_column_index: Optional new starting column index (0-based)
|
|
879
|
+
end_column_index: Optional new ending column index (exclusive)
|
|
880
|
+
column_properties: Optional list of column properties with types and validation rules. Valid column types: "TEXT", "PERCENT", "DROPDOWN", "DOUBLE", "CURRENCY", "DATE", "TIME", "DATE_TIME". Example: [{"columnIndex": 0, "columnName": "Model Number", "columnType": "TEXT"}, {"columnIndex": 1, "columnName": "Sales - Jan", "columnType": "DOUBLE"}, {"columnIndex": 2, "columnName": "Price", "columnType": "CURRENCY"}, {"columnIndex": 3, "columnName": "Progress", "columnType": "PERCENT"}, {"columnIndex": 4, "columnName": "Created Date", "columnType": "DATE"}, {"columnIndex": 5, "columnName": "Status", "columnType": "DROPDOWN", "dataValidationRule": {"condition": {"type": "ONE_OF_LIST", "values": [{"userEnteredValue": "Active"}, {"userEnteredValue": "Inactive"}]}}}]
|
|
881
|
+
|
|
882
|
+
Returns:
|
|
883
|
+
A dictionary containing the Google Sheets API response with the updated table details
|
|
884
|
+
|
|
885
|
+
Raises:
|
|
886
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
887
|
+
ValueError: When spreadsheet_id or table_id is empty or invalid parameters are provided
|
|
888
|
+
|
|
889
|
+
Tags:
|
|
890
|
+
update, table, modify, structured-data
|
|
891
|
+
"""
|
|
892
|
+
if not spreadsheet_id:
|
|
893
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
894
|
+
|
|
895
|
+
if not table_id:
|
|
896
|
+
raise ValueError("table_id cannot be empty")
|
|
897
|
+
|
|
898
|
+
# Validate indices if provided
|
|
899
|
+
if start_row_index is not None and start_row_index < 0:
|
|
900
|
+
raise ValueError("start_row_index must be non-negative")
|
|
901
|
+
|
|
902
|
+
if end_row_index is not None and end_row_index < 0:
|
|
903
|
+
raise ValueError("end_row_index must be non-negative")
|
|
904
|
+
|
|
905
|
+
if start_column_index is not None and start_column_index < 0:
|
|
906
|
+
raise ValueError("start_column_index must be non-negative")
|
|
907
|
+
|
|
908
|
+
if end_column_index is not None and end_column_index < 0:
|
|
909
|
+
raise ValueError("end_column_index must be non-negative")
|
|
910
|
+
|
|
911
|
+
if (
|
|
912
|
+
start_row_index is not None
|
|
913
|
+
and end_row_index is not None
|
|
914
|
+
and start_row_index >= end_row_index
|
|
915
|
+
):
|
|
916
|
+
raise ValueError("end_row_index must be greater than start_row_index")
|
|
917
|
+
|
|
918
|
+
if (
|
|
919
|
+
start_column_index is not None
|
|
920
|
+
and end_column_index is not None
|
|
921
|
+
and start_column_index >= end_column_index
|
|
922
|
+
):
|
|
923
|
+
raise ValueError("end_column_index must be greater than start_column_index")
|
|
924
|
+
|
|
925
|
+
# Validate column properties if provided
|
|
926
|
+
if column_properties:
|
|
927
|
+
valid_column_types = [
|
|
928
|
+
"TEXT",
|
|
929
|
+
"PERCENT",
|
|
930
|
+
"DROPDOWN",
|
|
931
|
+
"DOUBLE",
|
|
932
|
+
"CURRENCY",
|
|
933
|
+
"DATE",
|
|
934
|
+
"TIME",
|
|
935
|
+
"DATE_TIME",
|
|
936
|
+
]
|
|
937
|
+
for i, prop in enumerate(column_properties):
|
|
938
|
+
if (
|
|
939
|
+
"columnType" in prop
|
|
940
|
+
and prop["columnType"] not in valid_column_types
|
|
941
|
+
):
|
|
942
|
+
raise ValueError(
|
|
943
|
+
f"Invalid column type '{prop['columnType']}' at index {i}. Valid types are: {', '.join(valid_column_types)}"
|
|
944
|
+
)
|
|
945
|
+
|
|
946
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
947
|
+
|
|
948
|
+
# Build the table specification and track fields to update
|
|
949
|
+
table_spec: dict[str, Any] = {"tableId": table_id}
|
|
950
|
+
fields_to_update = []
|
|
951
|
+
|
|
952
|
+
# Add optional properties if provided
|
|
953
|
+
if table_name is not None:
|
|
954
|
+
table_spec["name"] = table_name
|
|
955
|
+
fields_to_update.append("name")
|
|
956
|
+
|
|
957
|
+
# Build range if any range parameters are provided
|
|
958
|
+
range_params: dict[str, Any] = {}
|
|
959
|
+
if start_row_index is not None:
|
|
960
|
+
range_params["startRowIndex"] = start_row_index
|
|
961
|
+
if end_row_index is not None:
|
|
962
|
+
range_params["endRowIndex"] = end_row_index
|
|
963
|
+
if start_column_index is not None:
|
|
964
|
+
range_params["startColumnIndex"] = start_column_index
|
|
965
|
+
if end_column_index is not None:
|
|
966
|
+
range_params["endColumnIndex"] = end_column_index
|
|
967
|
+
|
|
968
|
+
if range_params:
|
|
969
|
+
table_spec["range"] = range_params
|
|
970
|
+
fields_to_update.append("range")
|
|
971
|
+
|
|
972
|
+
# Add column properties if provided
|
|
973
|
+
if column_properties:
|
|
974
|
+
table_spec["columnProperties"] = column_properties
|
|
975
|
+
fields_to_update.append("columnProperties")
|
|
976
|
+
|
|
977
|
+
# Validate that at least one field is being updated
|
|
978
|
+
if not fields_to_update:
|
|
979
|
+
raise ValueError(
|
|
980
|
+
"At least one field must be provided for update (table_name, range indices, or column_properties)"
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
# Build the request body
|
|
984
|
+
request_body = {
|
|
985
|
+
"requests": [
|
|
986
|
+
{
|
|
987
|
+
"updateTable": {
|
|
988
|
+
"table": table_spec,
|
|
989
|
+
"fields": ",".join(fields_to_update),
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
]
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
response = self._post(url, data=request_body)
|
|
996
|
+
return self._handle_response(response)
|
|
997
|
+
|
|
998
|
+
def clear_values(self, spreadsheet_id: str, range: str) -> dict[str, Any]:
|
|
999
|
+
"""
|
|
1000
|
+
Clears all values from a specified range in a Google Spreadsheet while preserving cell formatting and other properties
|
|
1001
|
+
|
|
1002
|
+
Args:
|
|
1003
|
+
spreadsheet_id: The unique identifier of the Google Spreadsheet to modify
|
|
1004
|
+
range: The A1 or R1C1 notation range of cells to clear (e.g., 'Sheet1!A1:B2')
|
|
1005
|
+
|
|
1006
|
+
Returns:
|
|
1007
|
+
A dictionary containing the Google Sheets API response
|
|
1008
|
+
|
|
1009
|
+
Raises:
|
|
1010
|
+
HttpError: When the API request fails due to invalid spreadsheet_id, invalid range format, or insufficient permissions
|
|
1011
|
+
ValueError: When spreadsheet_id is empty or range is in invalid format
|
|
1012
|
+
|
|
1013
|
+
Tags:
|
|
1014
|
+
clear, modify, spreadsheet, api, sheets, data-management, important
|
|
1015
|
+
"""
|
|
1016
|
+
url = f"{self.base_url}/{spreadsheet_id}/values/{range}:clear"
|
|
1017
|
+
response = self._post(url, data={})
|
|
1018
|
+
return self._handle_response(response)
|
|
1019
|
+
|
|
1020
|
+
def update_values(
|
|
1021
|
+
self,
|
|
1022
|
+
spreadsheet_id: str,
|
|
1023
|
+
range: str,
|
|
1024
|
+
values: list[list[Any]],
|
|
1025
|
+
value_input_option: str = "RAW",
|
|
1026
|
+
) -> dict[str, Any]:
|
|
1027
|
+
"""
|
|
1028
|
+
Updates cell values in a specified range of a Google Spreadsheet using the Sheets API
|
|
1029
|
+
|
|
1030
|
+
Args:
|
|
1031
|
+
spreadsheet_id: The unique identifier of the target Google Spreadsheet
|
|
1032
|
+
range: The A1 notation range where values will be updated (e.g., 'Sheet1!A1:B2')
|
|
1033
|
+
values: A list of lists containing the data to write, where each inner list represents a row of values
|
|
1034
|
+
value_input_option: Determines how input data should be interpreted: 'RAW' (as-is) or 'USER_ENTERED' (parsed as UI input). Defaults to 'RAW'
|
|
1035
|
+
|
|
1036
|
+
Returns:
|
|
1037
|
+
A dictionary containing the Google Sheets API response with update details
|
|
1038
|
+
|
|
1039
|
+
Raises:
|
|
1040
|
+
RequestError: When the API request fails due to invalid parameters or network issues
|
|
1041
|
+
AuthenticationError: When authentication with the Google Sheets API fails
|
|
1042
|
+
|
|
1043
|
+
Tags:
|
|
1044
|
+
update, write, sheets, api, important, data-modification, google-sheets
|
|
1045
|
+
"""
|
|
1046
|
+
url = f"{self.base_url}/{spreadsheet_id}/values/{range}"
|
|
1047
|
+
params = {"valueInputOption": value_input_option}
|
|
1048
|
+
data = {"range": range, "values": values}
|
|
1049
|
+
response = self._put(url, data=data, params=params)
|
|
1050
|
+
return self._handle_response(response)
|
|
1051
|
+
|
|
1052
|
+
def batch_clear_values(
|
|
1053
|
+
self,
|
|
1054
|
+
spreadsheet_id: str,
|
|
1055
|
+
ranges: list[str],
|
|
1056
|
+
) -> dict[str, Any]:
|
|
1057
|
+
"""
|
|
1058
|
+
Tool to clear one or more ranges of values from a spreadsheet. use when you need to remove data from specific cells or ranges while keeping formatting and other properties intact.
|
|
1059
|
+
|
|
1060
|
+
Args:
|
|
1061
|
+
spreadsheet_id: The ID of the spreadsheet to update. Example: "1q2w3e4r5t6y7u8i9o0p"
|
|
1062
|
+
ranges: The ranges to clear, in A1 notation or R1C1 notation. Example: ["Sheet1!A1:B2", "Sheet1!C3:D4"]
|
|
1063
|
+
|
|
1064
|
+
Returns:
|
|
1065
|
+
A dictionary containing the Google Sheets API response with clear details
|
|
1066
|
+
|
|
1067
|
+
Raises:
|
|
1068
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1069
|
+
ValueError: When spreadsheet_id is empty or ranges is empty
|
|
1070
|
+
|
|
1071
|
+
Tags:
|
|
1072
|
+
clear, batch, values, spreadsheet
|
|
1073
|
+
"""
|
|
1074
|
+
if not spreadsheet_id:
|
|
1075
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1076
|
+
|
|
1077
|
+
if not ranges or not isinstance(ranges, list) or len(ranges) == 0:
|
|
1078
|
+
raise ValueError("ranges must be a non-empty list")
|
|
1079
|
+
|
|
1080
|
+
url = f"{self.base_url}/{spreadsheet_id}/values:batchClear"
|
|
1081
|
+
|
|
1082
|
+
request_body = {"ranges": ranges}
|
|
1083
|
+
|
|
1084
|
+
response = self._post(url, data=request_body)
|
|
1085
|
+
return self._handle_response(response)
|
|
1086
|
+
|
|
1087
|
+
def batch_get_values_by_data_filter(
|
|
1088
|
+
self,
|
|
1089
|
+
spreadsheet_id: str,
|
|
1090
|
+
data_filters: list[dict],
|
|
1091
|
+
major_dimension: str | None = None,
|
|
1092
|
+
value_render_option: str | None = None,
|
|
1093
|
+
date_time_render_option: str | None = None,
|
|
1094
|
+
) -> dict[str, Any]:
|
|
1095
|
+
"""
|
|
1096
|
+
Tool to return one or more ranges of values from a spreadsheet that match the specified data filters. use when you need to retrieve specific data sets based on filtering criteria rather than entire sheets or fixed ranges.
|
|
1097
|
+
|
|
1098
|
+
Args:
|
|
1099
|
+
spreadsheet_id: The ID of the spreadsheet to retrieve data from. Example: "1q2w3e4r5t6y7u8i9o0p"
|
|
1100
|
+
data_filters: The data filters used to match the ranges of values to retrieve. Ranges that match any of the specified data filters are included in the response. Each filter can contain:
|
|
1101
|
+
- a1Range: Selects data that matches the specified A1 range. Example: "Sheet1!A1:B5"
|
|
1102
|
+
- gridRange: Selects data that matches the specified grid range. Example: {"sheetId": 0, "startRowIndex": 0, "endRowIndex": 5, "startColumnIndex": 0, "endColumnIndex": 2}
|
|
1103
|
+
major_dimension: The major dimension that results should use. For example, if the spreadsheet data is: A1=1,B1=2,A2=3,B2=4, then a request that selects that range and sets majorDimension=ROWS returns [[1,2],[3,4]], whereas a request that sets majorDimension=COLUMNS returns [[1,3],[2,4]]. Options: "ROWS" or "COLUMNS". Example: "ROWS"
|
|
1104
|
+
value_render_option: How values should be represented in the output. The default render option is FORMATTED_VALUE. Options: "FORMATTED_VALUE", "UNFORMATTED_VALUE", or "FORMULA". Example: "FORMATTED_VALUE"
|
|
1105
|
+
date_time_render_option: How dates, times, and durations should be represented in the output. This is ignored if valueRenderOption is FORMATTED_VALUE. The default dateTime render option is SERIAL_NUMBER. Options: "SERIAL_NUMBER" or "FORMATTED_STRING". Example: "SERIAL_NUMBER"
|
|
1106
|
+
|
|
1107
|
+
Returns:
|
|
1108
|
+
A dictionary containing the filtered values that match the specified data filters
|
|
1109
|
+
|
|
1110
|
+
Raises:
|
|
1111
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1112
|
+
ValueError: When spreadsheet_id is empty or data_filters is empty
|
|
1113
|
+
|
|
1114
|
+
Tags:
|
|
1115
|
+
get, batch, data-filter, values, spreadsheet
|
|
1116
|
+
"""
|
|
1117
|
+
if not spreadsheet_id:
|
|
1118
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1119
|
+
|
|
1120
|
+
if (
|
|
1121
|
+
not data_filters
|
|
1122
|
+
or not isinstance(data_filters, list)
|
|
1123
|
+
or len(data_filters) == 0
|
|
1124
|
+
):
|
|
1125
|
+
raise ValueError("data_filters must be a non-empty list")
|
|
1126
|
+
|
|
1127
|
+
if major_dimension and major_dimension not in ["ROWS", "COLUMNS"]:
|
|
1128
|
+
raise ValueError('major_dimension must be either "ROWS" or "COLUMNS"')
|
|
1129
|
+
|
|
1130
|
+
if value_render_option and value_render_option not in [
|
|
1131
|
+
"FORMATTED_VALUE",
|
|
1132
|
+
"UNFORMATTED_VALUE",
|
|
1133
|
+
"FORMULA",
|
|
1134
|
+
]:
|
|
1135
|
+
raise ValueError(
|
|
1136
|
+
'value_render_option must be either "FORMATTED_VALUE", "UNFORMATTED_VALUE", or "FORMULA"'
|
|
1137
|
+
)
|
|
1138
|
+
|
|
1139
|
+
if date_time_render_option and date_time_render_option not in [
|
|
1140
|
+
"SERIAL_NUMBER",
|
|
1141
|
+
"FORMATTED_STRING",
|
|
1142
|
+
]:
|
|
1143
|
+
raise ValueError(
|
|
1144
|
+
'date_time_render_option must be either "SERIAL_NUMBER" or "FORMATTED_STRING"'
|
|
1145
|
+
)
|
|
1146
|
+
|
|
1147
|
+
url = f"{self.base_url}/{spreadsheet_id}/values:batchGetByDataFilter"
|
|
1148
|
+
|
|
1149
|
+
request_body: dict[str, Any] = {"dataFilters": data_filters}
|
|
1150
|
+
|
|
1151
|
+
# Add optional parameters if provided
|
|
1152
|
+
if major_dimension:
|
|
1153
|
+
request_body["majorDimension"] = major_dimension
|
|
1154
|
+
|
|
1155
|
+
if value_render_option:
|
|
1156
|
+
request_body["valueRenderOption"] = value_render_option
|
|
1157
|
+
|
|
1158
|
+
if date_time_render_option:
|
|
1159
|
+
request_body["dateTimeRenderOption"] = date_time_render_option
|
|
1160
|
+
|
|
1161
|
+
response = self._post(url, data=request_body)
|
|
1162
|
+
return self._handle_response(response)
|
|
1163
|
+
|
|
1164
|
+
def copy_to_sheet(
|
|
1165
|
+
self,
|
|
1166
|
+
spreadsheet_id: str,
|
|
1167
|
+
sheet_id: int,
|
|
1168
|
+
destination_spreadsheet_id: str,
|
|
1169
|
+
) -> dict[str, Any]:
|
|
1170
|
+
"""
|
|
1171
|
+
Tool to copy a single sheet from a spreadsheet to another spreadsheet. Use when you need to duplicate a sheet into a different spreadsheet.
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
Args:
|
|
1175
|
+
spreadsheet_id: The ID of the spreadsheet containing the sheet to copy. Example: "1qZ_..."
|
|
1176
|
+
sheet_id: The ID of the sheet to copy. Example: 0
|
|
1177
|
+
destination_spreadsheet_id: The ID of the spreadsheet to copy the sheet to. Example: "2rY_..."
|
|
1178
|
+
|
|
1179
|
+
Returns:
|
|
1180
|
+
A dictionary containing the Google Sheets API response with copy details
|
|
1181
|
+
|
|
1182
|
+
Raises:
|
|
1183
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1184
|
+
ValueError: When any required parameter is empty or invalid
|
|
1185
|
+
|
|
1186
|
+
Tags:
|
|
1187
|
+
copy, sheet, spreadsheet, duplicate
|
|
1188
|
+
"""
|
|
1189
|
+
if not spreadsheet_id:
|
|
1190
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1191
|
+
|
|
1192
|
+
if sheet_id is None:
|
|
1193
|
+
raise ValueError("sheet_id cannot be empty")
|
|
1194
|
+
|
|
1195
|
+
if not destination_spreadsheet_id:
|
|
1196
|
+
raise ValueError("destination_spreadsheet_id cannot be empty")
|
|
1197
|
+
|
|
1198
|
+
url = f"{self.base_url}/{spreadsheet_id}/sheets/{sheet_id}:copyTo"
|
|
1199
|
+
|
|
1200
|
+
request_body = {"destinationSpreadsheetId": destination_spreadsheet_id}
|
|
1201
|
+
|
|
1202
|
+
response = self._post(url, data=request_body)
|
|
1203
|
+
return self._handle_response(response)
|
|
1204
|
+
|
|
1205
|
+
def batch_update(
|
|
1206
|
+
self,
|
|
1207
|
+
spreadsheet_id: str,
|
|
1208
|
+
sheet_name: str,
|
|
1209
|
+
values: list[list[Any]],
|
|
1210
|
+
first_cell_location: str | None = None,
|
|
1211
|
+
value_input_option: str = "USER_ENTERED",
|
|
1212
|
+
include_values_in_response: bool = False,
|
|
1213
|
+
) -> dict[str, Any]:
|
|
1214
|
+
"""
|
|
1215
|
+
Updates a specified range in a google sheet with given values, or appends them as new rows if `first cell location` is omitted; ensure the target sheet exists and the spreadsheet contains at least one worksheet.
|
|
1216
|
+
Use this tool for basic updates/append. Overwrites existing data when appending.
|
|
1217
|
+
|
|
1218
|
+
Args:
|
|
1219
|
+
spreadsheet_id: The unique identifier of the Google Sheets spreadsheet to be updated. Example: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
|
|
1220
|
+
sheet_name: The name of the specific sheet within the spreadsheet to update. Example: "Sheet1"
|
|
1221
|
+
values: A 2D list of cell values. Each inner list represents a row. Values can be strings, numbers, or booleans. Ensure columns are properly aligned across rows. Example: [['Item', 'Cost', 'Stocked', 'Ship Date'], ['Wheel', 20.5, True, '2020-06-01'], ['Screw', 0.5, True, '2020-06-03'], ['Nut', 0.25, False, '2020-06-02']]
|
|
1222
|
+
first_cell_location: The starting cell for the update range, specified in A1 notation (e.g., 'A1', 'B2'). The update will extend from this cell to the right and down, based on the provided values. If omitted, values are appended to the end of the sheet. Example: "A1"
|
|
1223
|
+
value_input_option: How input data is interpreted. 'USER_ENTERED': Values parsed as if typed by a user (e.g., strings may become numbers/dates, formulas are calculated); recommended for formulas. 'RAW': Values stored as-is without parsing (e.g., '123' stays string, '=SUM(A1:B1)' stays string). Defaults to 'USER_ENTERED'. Example: "USER_ENTERED"
|
|
1224
|
+
include_values_in_response: If set to True, the response will include the updated values from the spreadsheet. Defaults to False. Example: True
|
|
1225
|
+
|
|
1226
|
+
Returns:
|
|
1227
|
+
A dictionary containing the Google Sheets API response with update details
|
|
1228
|
+
|
|
1229
|
+
Raises:
|
|
1230
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1231
|
+
ValueError: When spreadsheet_id is empty, sheet_name is empty, or values is empty
|
|
1232
|
+
|
|
1233
|
+
Tags:
|
|
1234
|
+
batch, update, write, sheets, api, important, data-modification, google-sheets
|
|
1235
|
+
"""
|
|
1236
|
+
if not spreadsheet_id:
|
|
1237
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1238
|
+
|
|
1239
|
+
if not sheet_name:
|
|
1240
|
+
raise ValueError("sheet_name cannot be empty")
|
|
1241
|
+
|
|
1242
|
+
if not values or not isinstance(values, list) or len(values) == 0:
|
|
1243
|
+
raise ValueError("values must be a non-empty 2D list")
|
|
1244
|
+
|
|
1245
|
+
if value_input_option not in ["RAW", "USER_ENTERED"]:
|
|
1246
|
+
raise ValueError(
|
|
1247
|
+
'value_input_option must be either "RAW" or "USER_ENTERED"'
|
|
1248
|
+
)
|
|
1249
|
+
|
|
1250
|
+
# Determine the range based on first_cell_location
|
|
1251
|
+
if first_cell_location:
|
|
1252
|
+
# Update specific range starting from first_cell_location
|
|
1253
|
+
range_str = f"{sheet_name}!{first_cell_location}"
|
|
1254
|
+
else:
|
|
1255
|
+
# Append to the sheet (no specific range)
|
|
1256
|
+
range_str = f"{sheet_name}"
|
|
1257
|
+
|
|
1258
|
+
url = f"{self.base_url}/{spreadsheet_id}/values/{range_str}"
|
|
1259
|
+
|
|
1260
|
+
params = {
|
|
1261
|
+
"valueInputOption": value_input_option,
|
|
1262
|
+
"includeValuesInResponse": include_values_in_response,
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
data = {"values": values}
|
|
1266
|
+
|
|
1267
|
+
response = self._put(url, data=data, params=params)
|
|
1268
|
+
return self._handle_response(response)
|
|
1269
|
+
|
|
1270
|
+
def append_values(
|
|
1271
|
+
self,
|
|
1272
|
+
spreadsheet_id: str,
|
|
1273
|
+
range: str,
|
|
1274
|
+
value_input_option: str,
|
|
1275
|
+
values: list[list[Any]],
|
|
1276
|
+
insert_data_option: str | None = None,
|
|
1277
|
+
include_values_in_response: bool | None = None,
|
|
1278
|
+
response_value_render_option: str | None = None,
|
|
1279
|
+
response_date_time_render_option: str | None = None,
|
|
1280
|
+
) -> dict[str, Any]:
|
|
1281
|
+
"""
|
|
1282
|
+
Tool to append values to a spreadsheet. use when you need to add new data to the end of an existing table in a google sheet.
|
|
1283
|
+
Use it for Insert new rows (INSERT_ROWS), specific range append, advanced options
|
|
1284
|
+
|
|
1285
|
+
Args:
|
|
1286
|
+
spreadsheet_id: The ID of the spreadsheet to update. Example: "1q0gLhLdGXYZblahblahblah"
|
|
1287
|
+
range: The A1 notation of a range to search for a logical table of data. Values are appended after the last row of the table. Example: "Sheet1!A1:B2"
|
|
1288
|
+
value_input_option: How the input data should be interpreted. Required. Options: "RAW" or "USER_ENTERED". Example: "USER_ENTERED"
|
|
1289
|
+
values: The data to be written. This is an array of arrays, the outer array representing all the data and each inner array representing a major dimension. Each item in the inner array corresponds with one cell. Example: [["A1_val1", "A1_val2"], ["A2_val1", "A2_val2"]]
|
|
1290
|
+
insert_data_option: How the input data should be inserted. Options: "OVERWRITE" or "INSERT_ROWS". Use "INSERT_ROWS" to add new rows instead of overwriting existing data. Example: "INSERT_ROWS"
|
|
1291
|
+
include_values_in_response: Determines if the update response should include the values of the cells that were appended. By default, responses do not include the updated values. Example: True
|
|
1292
|
+
response_value_render_option: Determines how values in the response should be rendered. The default render option is FORMATTED_VALUE. Options: "FORMATTED_VALUE", "UNFORMATTED_VALUE", or "FORMULA". Example: "FORMATTED_VALUE"
|
|
1293
|
+
response_date_time_render_option: Determines how dates, times, and durations in the response should be rendered. This is ignored if responseValueRenderOption is FORMATTED_VALUE. The default dateTime render option is SERIAL_NUMBER. Options: "SERIAL_NUMBER" or "FORMATTED_STRING". Example: "SERIAL_NUMBER"
|
|
1294
|
+
|
|
1295
|
+
Returns:
|
|
1296
|
+
A dictionary containing the Google Sheets API response with append details
|
|
1297
|
+
|
|
1298
|
+
Raises:
|
|
1299
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1300
|
+
ValueError: When required parameters are empty or invalid
|
|
1301
|
+
|
|
1302
|
+
Tags:
|
|
1303
|
+
append, values, spreadsheet, data, important
|
|
1304
|
+
"""
|
|
1305
|
+
if not spreadsheet_id:
|
|
1306
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1307
|
+
|
|
1308
|
+
if not range:
|
|
1309
|
+
raise ValueError("range cannot be empty")
|
|
1310
|
+
|
|
1311
|
+
if not value_input_option:
|
|
1312
|
+
raise ValueError("value_input_option cannot be empty")
|
|
1313
|
+
|
|
1314
|
+
if value_input_option not in ["RAW", "USER_ENTERED"]:
|
|
1315
|
+
raise ValueError(
|
|
1316
|
+
'value_input_option must be either "RAW" or "USER_ENTERED"'
|
|
1317
|
+
)
|
|
1318
|
+
|
|
1319
|
+
if not values or not isinstance(values, list) or len(values) == 0:
|
|
1320
|
+
raise ValueError("values must be a non-empty 2D list")
|
|
1321
|
+
|
|
1322
|
+
if insert_data_option and insert_data_option not in [
|
|
1323
|
+
"OVERWRITE",
|
|
1324
|
+
"INSERT_ROWS",
|
|
1325
|
+
]:
|
|
1326
|
+
raise ValueError(
|
|
1327
|
+
'insert_data_option must be either "OVERWRITE" or "INSERT_ROWS"'
|
|
1328
|
+
)
|
|
1329
|
+
|
|
1330
|
+
if response_value_render_option and response_value_render_option not in [
|
|
1331
|
+
"FORMATTED_VALUE",
|
|
1332
|
+
"UNFORMATTED_VALUE",
|
|
1333
|
+
"FORMULA",
|
|
1334
|
+
]:
|
|
1335
|
+
raise ValueError(
|
|
1336
|
+
'response_value_render_option must be either "FORMATTED_VALUE", "UNFORMATTED_VALUE", or "FORMULA"'
|
|
1337
|
+
)
|
|
1338
|
+
|
|
1339
|
+
if (
|
|
1340
|
+
response_date_time_render_option
|
|
1341
|
+
and response_date_time_render_option
|
|
1342
|
+
not in ["SERIAL_NUMBER", "FORMATTED_STRING"]
|
|
1343
|
+
):
|
|
1344
|
+
raise ValueError(
|
|
1345
|
+
'response_date_time_render_option must be either "SERIAL_NUMBER" or "FORMATTED_STRING"'
|
|
1346
|
+
)
|
|
1347
|
+
|
|
1348
|
+
url = f"{self.base_url}/{spreadsheet_id}/values/{range}:append"
|
|
1349
|
+
|
|
1350
|
+
params: dict[str, Any] = {"valueInputOption": value_input_option}
|
|
1351
|
+
|
|
1352
|
+
# Add optional parameters if provided
|
|
1353
|
+
if insert_data_option:
|
|
1354
|
+
params["insertDataOption"] = insert_data_option
|
|
1355
|
+
|
|
1356
|
+
if include_values_in_response is not None:
|
|
1357
|
+
params["includeValuesInResponse"] = include_values_in_response
|
|
1358
|
+
|
|
1359
|
+
if response_value_render_option:
|
|
1360
|
+
params["responseValueRenderOption"] = response_value_render_option
|
|
1361
|
+
|
|
1362
|
+
if response_date_time_render_option:
|
|
1363
|
+
params["responseDateTimeRenderOption"] = response_date_time_render_option
|
|
1364
|
+
|
|
1365
|
+
data = {"values": values}
|
|
1366
|
+
|
|
1367
|
+
response = self._post(url, data=data, params=params)
|
|
1368
|
+
return self._handle_response(response)
|
|
1369
|
+
|
|
1370
|
+
def clear_basic_filter(
|
|
1371
|
+
self,
|
|
1372
|
+
spreadsheet_id: str,
|
|
1373
|
+
sheet_id: int,
|
|
1374
|
+
) -> dict[str, Any]:
|
|
1375
|
+
"""
|
|
1376
|
+
Tool to clear the basic filter from a sheet. use when you need to remove an existing basic filter from a specific sheet within a google spreadsheet.
|
|
1377
|
+
|
|
1378
|
+
Args:
|
|
1379
|
+
spreadsheet_id: The ID of the spreadsheet. Example: "abc123xyz789"
|
|
1380
|
+
sheet_id: The ID of the sheet on which the basic filter should be cleared. Example: 0
|
|
1381
|
+
|
|
1382
|
+
Returns:
|
|
1383
|
+
A dictionary containing the Google Sheets API response with update details
|
|
1384
|
+
|
|
1385
|
+
Raises:
|
|
1386
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1387
|
+
ValueError: When spreadsheet_id is empty or sheet_id is negative
|
|
1388
|
+
|
|
1389
|
+
Tags:
|
|
1390
|
+
clear, filter, basic-filter, spreadsheet
|
|
1391
|
+
"""
|
|
1392
|
+
if not spreadsheet_id:
|
|
1393
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1394
|
+
|
|
1395
|
+
if sheet_id < 0:
|
|
1396
|
+
raise ValueError("sheet_id must be non-negative")
|
|
1397
|
+
|
|
1398
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
1399
|
+
|
|
1400
|
+
request_body = {"requests": [{"clearBasicFilter": {"sheetId": sheet_id}}]}
|
|
1401
|
+
|
|
1402
|
+
response = self._post(url, data=request_body)
|
|
1403
|
+
return self._handle_response(response)
|
|
1404
|
+
|
|
1405
|
+
def delete_sheet(
|
|
1406
|
+
self,
|
|
1407
|
+
spreadsheet_id: str,
|
|
1408
|
+
sheet_id: int,
|
|
1409
|
+
) -> dict[str, Any]:
|
|
1410
|
+
"""
|
|
1411
|
+
Tool to delete a sheet (worksheet) from a spreadsheet. use when you need to remove a specific sheet from a google sheet document.
|
|
1412
|
+
|
|
1413
|
+
Args:
|
|
1414
|
+
spreadsheet_id: The ID of the spreadsheet from which to delete the sheet. Example: "abc123xyz789"
|
|
1415
|
+
sheet_id: The ID of the sheet to delete. If the sheet is of DATA_SOURCE type, the associated DataSource is also deleted. Example: 123456789
|
|
1416
|
+
|
|
1417
|
+
Returns:
|
|
1418
|
+
A dictionary containing the Google Sheets API response with update details
|
|
1419
|
+
|
|
1420
|
+
Raises:
|
|
1421
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1422
|
+
ValueError: When spreadsheet_id is empty or sheet_id is negative
|
|
1423
|
+
|
|
1424
|
+
Tags:
|
|
1425
|
+
delete, sheet, spreadsheet, worksheet
|
|
1426
|
+
"""
|
|
1427
|
+
if not spreadsheet_id:
|
|
1428
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1429
|
+
|
|
1430
|
+
if sheet_id < 0:
|
|
1431
|
+
raise ValueError("sheet_id must be non-negative")
|
|
1432
|
+
|
|
1433
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
1434
|
+
|
|
1435
|
+
request_body = {"requests": [{"deleteSheet": {"sheetId": sheet_id}}]}
|
|
1436
|
+
|
|
1437
|
+
response = self._post(url, data=request_body)
|
|
1438
|
+
return self._handle_response(response)
|
|
1439
|
+
|
|
1440
|
+
def list_tables(
|
|
1441
|
+
self,
|
|
1442
|
+
spreadsheet_id: str,
|
|
1443
|
+
min_rows: int = 2,
|
|
1444
|
+
min_columns: int = 1,
|
|
1445
|
+
min_confidence: float = 0.5,
|
|
1446
|
+
) -> dict[str, Any]:
|
|
1447
|
+
"""
|
|
1448
|
+
This action is used to list all tables in a google spreadsheet, call this action to get the list of tables in a spreadsheet. discover all tables in a google spreadsheet by analyzing sheet structure and detecting data patterns. uses heuristic analysis to find header rows, data boundaries, and table structures.
|
|
1449
|
+
|
|
1450
|
+
Args:
|
|
1451
|
+
spreadsheet_id: Google Sheets ID from the URL (e.g., '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms'). Example: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
|
|
1452
|
+
min_rows: Minimum number of data rows to consider a valid table. Example: 2
|
|
1453
|
+
min_columns: Minimum number of columns to consider a valid table. Example: 1
|
|
1454
|
+
min_confidence: Minimum confidence score (0.0-1.0) to consider a valid table. Example: 0.5
|
|
1455
|
+
|
|
1456
|
+
Returns:
|
|
1457
|
+
A dictionary containing the list of discovered tables with their properties
|
|
1458
|
+
|
|
1459
|
+
Raises:
|
|
1460
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1461
|
+
ValueError: When spreadsheet_id is empty or parameters are invalid
|
|
1462
|
+
|
|
1463
|
+
Tags:
|
|
1464
|
+
list, tables, discover, analyze, spreadsheet, important
|
|
1465
|
+
"""
|
|
1466
|
+
if not spreadsheet_id:
|
|
1467
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1468
|
+
|
|
1469
|
+
if min_rows < 1:
|
|
1470
|
+
raise ValueError("min_rows must be at least 1")
|
|
1471
|
+
|
|
1472
|
+
if min_columns < 1:
|
|
1473
|
+
raise ValueError("min_columns must be at least 1")
|
|
1474
|
+
|
|
1475
|
+
if not 0 <= min_confidence <= 1:
|
|
1476
|
+
raise ValueError("min_confidence must be between 0.0 and 1.0")
|
|
1477
|
+
|
|
1478
|
+
# Get spreadsheet structure
|
|
1479
|
+
spreadsheet = self.get_spreadsheet(spreadsheet_id)
|
|
1480
|
+
|
|
1481
|
+
tables = []
|
|
1482
|
+
|
|
1483
|
+
for sheet in spreadsheet.get("sheets", []):
|
|
1484
|
+
sheet_properties = sheet.get("properties", {})
|
|
1485
|
+
sheet_id = sheet_properties.get("sheetId")
|
|
1486
|
+
sheet_title = sheet_properties.get("title", "Sheet1")
|
|
1487
|
+
|
|
1488
|
+
# Analyze sheet for tables using helper function
|
|
1489
|
+
sheet_tables = analyze_sheet_for_tables(
|
|
1490
|
+
self.get_values, # Pass the get_values method as a function
|
|
1491
|
+
spreadsheet_id,
|
|
1492
|
+
sheet_id,
|
|
1493
|
+
sheet_title,
|
|
1494
|
+
min_rows,
|
|
1495
|
+
min_columns,
|
|
1496
|
+
min_confidence,
|
|
1497
|
+
)
|
|
1498
|
+
|
|
1499
|
+
tables.extend(sheet_tables)
|
|
1500
|
+
|
|
1501
|
+
return {
|
|
1502
|
+
"spreadsheet_id": spreadsheet_id,
|
|
1503
|
+
"total_tables": len(tables),
|
|
1504
|
+
"tables": tables,
|
|
1505
|
+
"analysis_parameters": {
|
|
1506
|
+
"min_rows": min_rows,
|
|
1507
|
+
"min_columns": min_columns,
|
|
1508
|
+
},
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
def get_table_schema(
|
|
1512
|
+
self,
|
|
1513
|
+
spreadsheet_id: str,
|
|
1514
|
+
table_name: str,
|
|
1515
|
+
sheet_name: str | None = None,
|
|
1516
|
+
sample_size: int = 50,
|
|
1517
|
+
) -> dict[str, Any]:
|
|
1518
|
+
"""
|
|
1519
|
+
Analyzes table structure and infers column names, types, and constraints.
|
|
1520
|
+
Uses statistical analysis of sample data to determine the most likely data type for each column.
|
|
1521
|
+
Call this action after calling the list tables action to get the schema of a table in a spreadsheet.
|
|
1522
|
+
|
|
1523
|
+
Args:
|
|
1524
|
+
spreadsheet_id: Google Sheets ID from the URL (e.g., '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms')
|
|
1525
|
+
table_name: Specific table name from LIST_TABLES response (e.g., 'Sales_Data', 'Employee_List'). Use 'auto' to analyze the largest/most prominent table
|
|
1526
|
+
sheet_name: Sheet/tab name if table_name is ambiguous across multiple sheets
|
|
1527
|
+
sample_size: Number of rows to sample for type inference (1-1000, default 50)
|
|
1528
|
+
|
|
1529
|
+
Returns:
|
|
1530
|
+
A dictionary containing the table schema with column names, types, and constraints
|
|
1531
|
+
|
|
1532
|
+
Raises:
|
|
1533
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1534
|
+
ValueError: When spreadsheet_id is empty, table_name is empty, or sample_size is invalid
|
|
1535
|
+
|
|
1536
|
+
Tags:
|
|
1537
|
+
schema, analyze, table, structure, types, columns
|
|
1538
|
+
"""
|
|
1539
|
+
if not spreadsheet_id:
|
|
1540
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1541
|
+
|
|
1542
|
+
if not table_name:
|
|
1543
|
+
raise ValueError("table_name cannot be empty")
|
|
1544
|
+
|
|
1545
|
+
if not 1 <= sample_size <= 1000:
|
|
1546
|
+
raise ValueError("sample_size must be between 1 and 1000")
|
|
1547
|
+
|
|
1548
|
+
# Get spreadsheet structure
|
|
1549
|
+
spreadsheet = self.get_spreadsheet(spreadsheet_id)
|
|
1550
|
+
|
|
1551
|
+
# Find the target table
|
|
1552
|
+
target_table = None
|
|
1553
|
+
|
|
1554
|
+
for sheet in spreadsheet.get("sheets", []):
|
|
1555
|
+
sheet_properties = sheet.get("properties", {})
|
|
1556
|
+
sheet_title = sheet_properties.get("title", "Sheet1")
|
|
1557
|
+
|
|
1558
|
+
# If sheet_name is specified, only look in that sheet
|
|
1559
|
+
if sheet_name and sheet_title != sheet_name:
|
|
1560
|
+
continue
|
|
1561
|
+
|
|
1562
|
+
# Get tables in this sheet
|
|
1563
|
+
sheet_tables = analyze_sheet_for_tables(
|
|
1564
|
+
self.get_values,
|
|
1565
|
+
spreadsheet_id,
|
|
1566
|
+
sheet_properties.get("sheetId", 0),
|
|
1567
|
+
sheet_title,
|
|
1568
|
+
min_rows=2,
|
|
1569
|
+
min_columns=1,
|
|
1570
|
+
min_confidence=0.3,
|
|
1571
|
+
)
|
|
1572
|
+
|
|
1573
|
+
for table in sheet_tables:
|
|
1574
|
+
if table_name == "auto":
|
|
1575
|
+
# For auto mode, select the largest table
|
|
1576
|
+
if target_table is None or (
|
|
1577
|
+
table["rows"] * table["columns"]
|
|
1578
|
+
> target_table["rows"] * target_table["columns"]
|
|
1579
|
+
):
|
|
1580
|
+
target_table = table
|
|
1581
|
+
elif table["table_name"] == table_name:
|
|
1582
|
+
target_table = table
|
|
1583
|
+
break
|
|
1584
|
+
|
|
1585
|
+
if target_table and table_name != "auto":
|
|
1586
|
+
break
|
|
1587
|
+
|
|
1588
|
+
if not target_table:
|
|
1589
|
+
raise ValueError(f"Table '{table_name}' not found in spreadsheet")
|
|
1590
|
+
|
|
1591
|
+
# Use the helper function to analyze the table schema
|
|
1592
|
+
return analyze_table_schema(
|
|
1593
|
+
self.get_values, spreadsheet_id, target_table, sample_size
|
|
1594
|
+
)
|
|
1595
|
+
|
|
1596
|
+
def set_basic_filter(
|
|
1597
|
+
self,
|
|
1598
|
+
spreadsheet_id: str,
|
|
1599
|
+
filter: dict,
|
|
1600
|
+
) -> dict[str, Any]:
|
|
1601
|
+
"""
|
|
1602
|
+
Tool to set a basic filter on a sheet in a google spreadsheet. use when you need to filter or sort data within a specific range on a sheet.
|
|
1603
|
+
|
|
1604
|
+
Args:
|
|
1605
|
+
spreadsheet_id: The ID of the spreadsheet. Example: "abc123xyz789"
|
|
1606
|
+
filter: The filter to set. This parameter is required. Contains:
|
|
1607
|
+
- range: The range the filter covers (required)
|
|
1608
|
+
- sheetId: The sheet this range is on (required)
|
|
1609
|
+
- startRowIndex: The start row (inclusive) of the range (optional)
|
|
1610
|
+
- endRowIndex: The end row (exclusive) of the range (optional)
|
|
1611
|
+
- startColumnIndex: The start column (inclusive) of the range (optional)
|
|
1612
|
+
- endColumnIndex: The end column (exclusive) of the range (optional)
|
|
1613
|
+
- sortSpecs: The sort specifications for the filter (optional)
|
|
1614
|
+
- dimensionIndex: The dimension the sort should be applied to
|
|
1615
|
+
- sortOrder: The order data should be sorted ("ASCENDING", "DESCENDING", "SORT_ORDER_UNSPECIFIED")
|
|
1616
|
+
|
|
1617
|
+
Returns:
|
|
1618
|
+
A dictionary containing the Google Sheets API response with filter details
|
|
1619
|
+
|
|
1620
|
+
Raises:
|
|
1621
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1622
|
+
ValueError: When spreadsheet_id is empty or filter is missing required fields
|
|
1623
|
+
|
|
1624
|
+
Tags:
|
|
1625
|
+
filter, basic-filter, spreadsheet, sort, important
|
|
1626
|
+
"""
|
|
1627
|
+
if not spreadsheet_id:
|
|
1628
|
+
raise ValueError("spreadsheet_id cannot be empty")
|
|
1629
|
+
|
|
1630
|
+
if not filter:
|
|
1631
|
+
raise ValueError("filter cannot be empty")
|
|
1632
|
+
|
|
1633
|
+
# Validate required filter fields
|
|
1634
|
+
if "range" not in filter:
|
|
1635
|
+
raise ValueError("filter must contain 'range' field")
|
|
1636
|
+
|
|
1637
|
+
# Validate required filter fields using Google API naming convention
|
|
1638
|
+
range_data = filter["range"]
|
|
1639
|
+
if "sheetId" not in range_data:
|
|
1640
|
+
raise ValueError("filter range must contain 'sheetId' field")
|
|
1641
|
+
|
|
1642
|
+
url = f"{self.base_url}/{spreadsheet_id}:batchUpdate"
|
|
1643
|
+
|
|
1644
|
+
request_body = {"requests": [{"setBasicFilter": {"filter": filter}}]}
|
|
1645
|
+
|
|
1646
|
+
response = self._post(url, data=request_body)
|
|
1647
|
+
return self._handle_response(response)
|
|
1648
|
+
|
|
1649
|
+
def format_cells(
|
|
1650
|
+
self,
|
|
1651
|
+
spreadsheetId: str,
|
|
1652
|
+
worksheetId: int,
|
|
1653
|
+
startRowIndex: int,
|
|
1654
|
+
startColumnIndex: int,
|
|
1655
|
+
endRowIndex: int,
|
|
1656
|
+
endColumnIndex: int,
|
|
1657
|
+
# Text formatting
|
|
1658
|
+
bold: bool | None = None,
|
|
1659
|
+
italic: bool | None = None,
|
|
1660
|
+
underline: bool | None = None,
|
|
1661
|
+
strikethrough: bool | None = None,
|
|
1662
|
+
fontSize: int | None = None,
|
|
1663
|
+
fontFamily: str | None = None,
|
|
1664
|
+
# Colors
|
|
1665
|
+
backgroundRed: float | None = None,
|
|
1666
|
+
backgroundGreen: float | None = None,
|
|
1667
|
+
backgroundBlue: float | None = None,
|
|
1668
|
+
textRed: float | None = None,
|
|
1669
|
+
textGreen: float | None = None,
|
|
1670
|
+
textBlue: float | None = None,
|
|
1671
|
+
# Alignment
|
|
1672
|
+
horizontalAlignment: str | None = None, # "LEFT", "CENTER", "RIGHT"
|
|
1673
|
+
verticalAlignment: str | None = None, # "TOP", "MIDDLE", "BOTTOM"
|
|
1674
|
+
# Text wrapping
|
|
1675
|
+
wrapStrategy: str
|
|
1676
|
+
| None = None, # "OVERFLOW_CELL", "LEGACY_WRAP", "CLIP", "WRAP"
|
|
1677
|
+
# Number format
|
|
1678
|
+
numberFormat: str | None = None,
|
|
1679
|
+
# Borders
|
|
1680
|
+
borderTop: dict | None = None,
|
|
1681
|
+
borderBottom: dict | None = None,
|
|
1682
|
+
borderLeft: dict | None = None,
|
|
1683
|
+
borderRight: dict | None = None,
|
|
1684
|
+
# Merge cells
|
|
1685
|
+
mergeCells: bool = False,
|
|
1686
|
+
) -> dict[str, Any]:
|
|
1687
|
+
"""
|
|
1688
|
+
Applies comprehensive cell formatting to a specified range in a Google Sheets worksheet.
|
|
1689
|
+
Supports background colors, text colors, borders, text formatting, font properties,
|
|
1690
|
+
alignment, number formats, text wrapping, and cell merging.
|
|
1691
|
+
|
|
1692
|
+
Args:
|
|
1693
|
+
spreadsheetId: Identifier of the Google Sheets spreadsheet. Example: "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms"
|
|
1694
|
+
worksheetId: ID (sheetId) of the worksheet. Use `get_spreadsheet` to find this ID. Example: 123456789
|
|
1695
|
+
startRowIndex: 0-based index of the first row in the range. Example: 0
|
|
1696
|
+
startColumnIndex: 0-based index of the first column in the range. Example: 0
|
|
1697
|
+
endRowIndex: 0-based index of the row *after* the last row in the range (exclusive). Example: 1
|
|
1698
|
+
endColumnIndex: 0-based index of the column *after* the last column in the range (exclusive). Example: 2
|
|
1699
|
+
|
|
1700
|
+
|
|
1701
|
+
bold: Apply bold formatting. Example: True
|
|
1702
|
+
italic: Apply italic formatting. Example: False
|
|
1703
|
+
underline: Apply underline formatting. Example: False
|
|
1704
|
+
strikethrough: Apply strikethrough formatting. Example: False
|
|
1705
|
+
fontSize: Font size in points. Example: 12
|
|
1706
|
+
fontFamily: Font family name. Example: "Arial", "Times New Roman"
|
|
1707
|
+
|
|
1708
|
+
backgroundRed: Red component of background color. Example: 0.9
|
|
1709
|
+
backgroundGreen: Green component of background color. Example: 0.9
|
|
1710
|
+
backgroundBlue: Blue component of background color. Example: 0.9
|
|
1711
|
+
|
|
1712
|
+
textRed: Red component of text color. Example: 0.0
|
|
1713
|
+
textGreen: Green component of text color. Example: 0.0
|
|
1714
|
+
textBlue: Blue component of text color. Example: 0.0
|
|
1715
|
+
|
|
1716
|
+
horizontalAlignment: "LEFT", "CENTER", or "RIGHT". Example: "CENTER"
|
|
1717
|
+
verticalAlignment: "TOP", "MIDDLE", or "BOTTOM". Example: "MIDDLE"
|
|
1718
|
+
|
|
1719
|
+
wrapStrategy: "OVERFLOW_CELL", "LEGACY_WRAP", "CLIP", or "WRAP". Example: "WRAP"
|
|
1720
|
+
|
|
1721
|
+
numberFormat: Number format string. Example: "#,##0.00", "0.00%", "$#,##0.00"
|
|
1722
|
+
|
|
1723
|
+
borderTop: Top border settings. Example: {"style": "SOLID", "color": {"red": 0, "green": 0, "blue": 0}}
|
|
1724
|
+
borderBottom: Bottom border settings. Example: {"style": "SOLID", "color": {"red": 0, "green": 0, "blue": 0}}
|
|
1725
|
+
borderLeft: Left border settings. Example: {"style": "SOLID", "color": {"red": 0, "green": 0, "blue": 0}}
|
|
1726
|
+
borderRight: Right border settings. Example: {"style": "SOLID", "color": {"red": 0, "green": 0, "blue": 0}}
|
|
1727
|
+
|
|
1728
|
+
mergeCells: Whether to merge the specified range into a single cell. Example: True
|
|
1729
|
+
|
|
1730
|
+
Returns:
|
|
1731
|
+
A dictionary containing the Google Sheets API response with formatting details
|
|
1732
|
+
|
|
1733
|
+
Raises:
|
|
1734
|
+
HTTPError: When the API request fails due to invalid parameters or insufficient permissions
|
|
1735
|
+
ValueError: When spreadsheet_id is empty, indices are invalid, or color values are out of range
|
|
1736
|
+
|
|
1737
|
+
Tags:
|
|
1738
|
+
format, cells, styling, text-formatting, background-color, borders, alignment, merge
|
|
1739
|
+
"""
|
|
1740
|
+
if not spreadsheetId:
|
|
1741
|
+
raise ValueError("spreadsheetId cannot be empty")
|
|
1742
|
+
|
|
1743
|
+
if worksheetId < 0:
|
|
1744
|
+
raise ValueError("worksheetId must be non-negative")
|
|
1745
|
+
|
|
1746
|
+
if (
|
|
1747
|
+
startRowIndex < 0
|
|
1748
|
+
or startColumnIndex < 0
|
|
1749
|
+
or endRowIndex < 0
|
|
1750
|
+
or endColumnIndex < 0
|
|
1751
|
+
):
|
|
1752
|
+
raise ValueError("All indices must be non-negative")
|
|
1753
|
+
|
|
1754
|
+
if startRowIndex >= endRowIndex:
|
|
1755
|
+
raise ValueError("endRowIndex must be greater than startRowIndex")
|
|
1756
|
+
|
|
1757
|
+
if startColumnIndex >= endColumnIndex:
|
|
1758
|
+
raise ValueError("endColumnIndex must be greater than startColumnIndex")
|
|
1759
|
+
|
|
1760
|
+
# Validate color values if provided
|
|
1761
|
+
for color_name, color_value in [
|
|
1762
|
+
("backgroundRed", backgroundRed),
|
|
1763
|
+
("backgroundGreen", backgroundGreen),
|
|
1764
|
+
("backgroundBlue", backgroundBlue),
|
|
1765
|
+
("textRed", textRed),
|
|
1766
|
+
("textGreen", textGreen),
|
|
1767
|
+
("textBlue", textBlue),
|
|
1768
|
+
]:
|
|
1769
|
+
if color_value is not None and not 0 <= color_value <= 1:
|
|
1770
|
+
raise ValueError(f"{color_name} must be between 0.0 and 1.0")
|
|
1771
|
+
|
|
1772
|
+
if fontSize is not None and fontSize <= 0:
|
|
1773
|
+
raise ValueError("fontSize must be positive")
|
|
1774
|
+
|
|
1775
|
+
if horizontalAlignment and horizontalAlignment not in [
|
|
1776
|
+
"LEFT",
|
|
1777
|
+
"CENTER",
|
|
1778
|
+
"RIGHT",
|
|
1779
|
+
]:
|
|
1780
|
+
raise ValueError('horizontalAlignment must be "LEFT", "CENTER", or "RIGHT"')
|
|
1781
|
+
|
|
1782
|
+
if verticalAlignment and verticalAlignment not in ["TOP", "MIDDLE", "BOTTOM"]:
|
|
1783
|
+
raise ValueError('verticalAlignment must be "TOP", "MIDDLE", or "BOTTOM"')
|
|
1784
|
+
|
|
1785
|
+
if wrapStrategy and wrapStrategy not in [
|
|
1786
|
+
"OVERFLOW_CELL",
|
|
1787
|
+
"LEGACY_WRAP",
|
|
1788
|
+
"CLIP",
|
|
1789
|
+
"WRAP",
|
|
1790
|
+
]:
|
|
1791
|
+
raise ValueError(
|
|
1792
|
+
'wrapStrategy must be "OVERFLOW_CELL", "LEGACY_WRAP", "CLIP", or "WRAP"'
|
|
1793
|
+
)
|
|
1794
|
+
|
|
1795
|
+
url = f"{self.base_url}/{spreadsheetId}:batchUpdate"
|
|
1796
|
+
|
|
1797
|
+
requests = []
|
|
1798
|
+
|
|
1799
|
+
# Handle cell merging first if requested
|
|
1800
|
+
if mergeCells:
|
|
1801
|
+
requests.append(
|
|
1802
|
+
{
|
|
1803
|
+
"mergeCells": {
|
|
1804
|
+
"range": {
|
|
1805
|
+
"sheetId": worksheetId,
|
|
1806
|
+
"startRowIndex": startRowIndex,
|
|
1807
|
+
"endRowIndex": endRowIndex,
|
|
1808
|
+
"startColumnIndex": startColumnIndex,
|
|
1809
|
+
"endColumnIndex": endColumnIndex,
|
|
1810
|
+
},
|
|
1811
|
+
"mergeType": "MERGE_ALL",
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
)
|
|
1815
|
+
|
|
1816
|
+
# Build the cell format request
|
|
1817
|
+
cell_format = {}
|
|
1818
|
+
|
|
1819
|
+
# Text format
|
|
1820
|
+
text_format = {}
|
|
1821
|
+
if bold is not None:
|
|
1822
|
+
text_format["bold"] = bold
|
|
1823
|
+
if italic is not None:
|
|
1824
|
+
text_format["italic"] = italic
|
|
1825
|
+
if underline is not None:
|
|
1826
|
+
text_format["underline"] = underline
|
|
1827
|
+
if strikethrough is not None:
|
|
1828
|
+
text_format["strikethrough"] = strikethrough
|
|
1829
|
+
if fontSize is not None:
|
|
1830
|
+
text_format["fontSize"] = fontSize
|
|
1831
|
+
if fontFamily is not None:
|
|
1832
|
+
text_format["fontFamily"] = fontFamily
|
|
1833
|
+
|
|
1834
|
+
# Text color
|
|
1835
|
+
if any(color is not None for color in [textRed, textGreen, textBlue]):
|
|
1836
|
+
text_color = {}
|
|
1837
|
+
if textRed is not None:
|
|
1838
|
+
text_color["red"] = textRed
|
|
1839
|
+
if textGreen is not None:
|
|
1840
|
+
text_color["green"] = textGreen
|
|
1841
|
+
if textBlue is not None:
|
|
1842
|
+
text_color["blue"] = textBlue
|
|
1843
|
+
if text_color:
|
|
1844
|
+
text_format["foregroundColor"] = {"rgbColor": text_color}
|
|
1845
|
+
|
|
1846
|
+
if text_format:
|
|
1847
|
+
cell_format["textFormat"] = text_format
|
|
1848
|
+
|
|
1849
|
+
# Background color
|
|
1850
|
+
if any(
|
|
1851
|
+
color is not None
|
|
1852
|
+
for color in [backgroundRed, backgroundGreen, backgroundBlue]
|
|
1853
|
+
):
|
|
1854
|
+
background_color = {}
|
|
1855
|
+
if backgroundRed is not None:
|
|
1856
|
+
background_color["red"] = backgroundRed
|
|
1857
|
+
if backgroundGreen is not None:
|
|
1858
|
+
background_color["green"] = backgroundGreen
|
|
1859
|
+
if backgroundBlue is not None:
|
|
1860
|
+
background_color["blue"] = backgroundBlue
|
|
1861
|
+
if background_color:
|
|
1862
|
+
cell_format["backgroundColorStyle"] = {"rgbColor": background_color}
|
|
1863
|
+
|
|
1864
|
+
# Alignment
|
|
1865
|
+
if horizontalAlignment or verticalAlignment:
|
|
1866
|
+
cell_format["horizontalAlignment"] = horizontalAlignment
|
|
1867
|
+
cell_format["verticalAlignment"] = verticalAlignment
|
|
1868
|
+
|
|
1869
|
+
# Text wrapping
|
|
1870
|
+
if wrapStrategy:
|
|
1871
|
+
cell_format["wrapStrategy"] = wrapStrategy
|
|
1872
|
+
|
|
1873
|
+
# Number format
|
|
1874
|
+
if numberFormat:
|
|
1875
|
+
cell_format["numberFormat"] = {"type": "TEXT", "pattern": numberFormat}
|
|
1876
|
+
|
|
1877
|
+
# Borders
|
|
1878
|
+
borders = {}
|
|
1879
|
+
for border_side, border_config in [
|
|
1880
|
+
("top", borderTop),
|
|
1881
|
+
("bottom", borderBottom),
|
|
1882
|
+
("left", borderLeft),
|
|
1883
|
+
("right", borderRight),
|
|
1884
|
+
]:
|
|
1885
|
+
if border_config:
|
|
1886
|
+
borders[border_side] = border_config
|
|
1887
|
+
|
|
1888
|
+
if borders:
|
|
1889
|
+
cell_format["borders"] = borders
|
|
1890
|
+
|
|
1891
|
+
# Add cell formatting request if any formatting is specified
|
|
1892
|
+
if cell_format:
|
|
1893
|
+
requests.append(
|
|
1894
|
+
{
|
|
1895
|
+
"repeatCell": {
|
|
1896
|
+
"range": {
|
|
1897
|
+
"sheetId": worksheetId,
|
|
1898
|
+
"startRowIndex": startRowIndex,
|
|
1899
|
+
"endRowIndex": endRowIndex,
|
|
1900
|
+
"startColumnIndex": startColumnIndex,
|
|
1901
|
+
"endColumnIndex": endColumnIndex,
|
|
1902
|
+
},
|
|
1903
|
+
"cell": {"userEnteredFormat": cell_format},
|
|
1904
|
+
"fields": "userEnteredFormat",
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
)
|
|
1908
|
+
|
|
1909
|
+
request_body = {"requests": requests}
|
|
1910
|
+
response = self._post(url, data=request_body)
|
|
1911
|
+
return self._handle_response(response)
|
|
1912
|
+
|
|
1913
|
+
def list_tools(self):
|
|
1914
|
+
"""Returns a list of methods exposed as tools."""
|
|
1915
|
+
return [
|
|
1916
|
+
self.create_spreadsheet,
|
|
1917
|
+
self.get_spreadsheet,
|
|
1918
|
+
self.batch_get_values,
|
|
1919
|
+
self.insert_dimensions,
|
|
1920
|
+
self.append_dimensions,
|
|
1921
|
+
self.delete_dimensions,
|
|
1922
|
+
self.add_sheet,
|
|
1923
|
+
self.delete_sheet,
|
|
1924
|
+
self.add_basic_chart,
|
|
1925
|
+
self.add_pie_chart,
|
|
1926
|
+
self.add_table,
|
|
1927
|
+
self.update_table,
|
|
1928
|
+
self.clear_values,
|
|
1929
|
+
self.update_values,
|
|
1930
|
+
self.batch_update,
|
|
1931
|
+
self.clear_basic_filter,
|
|
1932
|
+
self.list_tables,
|
|
1933
|
+
self.get_values,
|
|
1934
|
+
self.get_table_schema,
|
|
1935
|
+
self.set_basic_filter,
|
|
1936
|
+
self.copy_to_sheet,
|
|
1937
|
+
self.append_values,
|
|
1938
|
+
self.batch_clear_values,
|
|
1939
|
+
self.batch_get_values_by_data_filter,
|
|
1940
|
+
self.format_cells,
|
|
1941
|
+
]
|