universal-mcp-applications 0.1.22__py3-none-any.whl → 0.1.39rc8__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.

Potentially problematic release.


This version of universal-mcp-applications might be problematic. Click here for more details.

Files changed (120) hide show
  1. universal_mcp/applications/ahrefs/app.py +92 -238
  2. universal_mcp/applications/airtable/app.py +23 -122
  3. universal_mcp/applications/apollo/app.py +122 -475
  4. universal_mcp/applications/asana/app.py +605 -1755
  5. universal_mcp/applications/aws_s3/app.py +36 -103
  6. universal_mcp/applications/bill/app.py +644 -2055
  7. universal_mcp/applications/box/app.py +1246 -4159
  8. universal_mcp/applications/braze/app.py +410 -1476
  9. universal_mcp/applications/browser_use/README.md +15 -1
  10. universal_mcp/applications/browser_use/__init__.py +1 -0
  11. universal_mcp/applications/browser_use/app.py +94 -37
  12. universal_mcp/applications/cal_com_v2/app.py +207 -625
  13. universal_mcp/applications/calendly/app.py +103 -242
  14. universal_mcp/applications/canva/app.py +75 -140
  15. universal_mcp/applications/clickup/app.py +331 -798
  16. universal_mcp/applications/coda/app.py +240 -520
  17. universal_mcp/applications/confluence/app.py +497 -1285
  18. universal_mcp/applications/contentful/app.py +36 -151
  19. universal_mcp/applications/crustdata/app.py +42 -121
  20. universal_mcp/applications/dialpad/app.py +451 -924
  21. universal_mcp/applications/digitalocean/app.py +2071 -6082
  22. universal_mcp/applications/domain_checker/app.py +3 -54
  23. universal_mcp/applications/e2b/app.py +14 -64
  24. universal_mcp/applications/elevenlabs/app.py +9 -47
  25. universal_mcp/applications/exa/README.md +8 -4
  26. universal_mcp/applications/exa/app.py +408 -186
  27. universal_mcp/applications/falai/app.py +24 -101
  28. universal_mcp/applications/figma/app.py +91 -175
  29. universal_mcp/applications/file_system/app.py +2 -13
  30. universal_mcp/applications/firecrawl/app.py +186 -163
  31. universal_mcp/applications/fireflies/app.py +59 -281
  32. universal_mcp/applications/fpl/app.py +92 -529
  33. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  34. universal_mcp/applications/fpl/utils/helper.py +25 -89
  35. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  36. universal_mcp/applications/ghost_content/app.py +66 -175
  37. universal_mcp/applications/github/app.py +28 -65
  38. universal_mcp/applications/gong/app.py +140 -300
  39. universal_mcp/applications/google_calendar/app.py +26 -78
  40. universal_mcp/applications/google_docs/app.py +324 -354
  41. universal_mcp/applications/google_drive/app.py +194 -793
  42. universal_mcp/applications/google_gemini/app.py +29 -64
  43. universal_mcp/applications/google_mail/README.md +1 -0
  44. universal_mcp/applications/google_mail/app.py +93 -214
  45. universal_mcp/applications/google_searchconsole/app.py +25 -58
  46. universal_mcp/applications/google_sheet/app.py +174 -623
  47. universal_mcp/applications/google_sheet/helper.py +26 -53
  48. universal_mcp/applications/hashnode/app.py +57 -269
  49. universal_mcp/applications/heygen/app.py +77 -155
  50. universal_mcp/applications/http_tools/app.py +10 -32
  51. universal_mcp/applications/hubspot/README.md +1 -1
  52. universal_mcp/applications/hubspot/app.py +7508 -99
  53. universal_mcp/applications/jira/app.py +2419 -8334
  54. universal_mcp/applications/klaviyo/app.py +737 -1619
  55. universal_mcp/applications/linkedin/README.md +23 -4
  56. universal_mcp/applications/linkedin/app.py +861 -155
  57. universal_mcp/applications/mailchimp/app.py +696 -1851
  58. universal_mcp/applications/markitdown/app.py +8 -20
  59. universal_mcp/applications/miro/app.py +333 -815
  60. universal_mcp/applications/ms_teams/app.py +85 -207
  61. universal_mcp/applications/neon/app.py +144 -250
  62. universal_mcp/applications/notion/app.py +36 -51
  63. universal_mcp/applications/onedrive/README.md +24 -0
  64. universal_mcp/applications/onedrive/__init__.py +1 -0
  65. universal_mcp/applications/onedrive/app.py +316 -0
  66. universal_mcp/applications/openai/app.py +42 -165
  67. universal_mcp/applications/outlook/README.md +22 -9
  68. universal_mcp/applications/outlook/app.py +606 -262
  69. universal_mcp/applications/perplexity/README.md +2 -1
  70. universal_mcp/applications/perplexity/app.py +162 -20
  71. universal_mcp/applications/pipedrive/app.py +1021 -3331
  72. universal_mcp/applications/posthog/app.py +272 -541
  73. universal_mcp/applications/reddit/app.py +88 -204
  74. universal_mcp/applications/resend/app.py +41 -107
  75. universal_mcp/applications/retell/app.py +23 -50
  76. universal_mcp/applications/rocketlane/app.py +250 -963
  77. universal_mcp/applications/scraper/README.md +7 -4
  78. universal_mcp/applications/scraper/app.py +245 -283
  79. universal_mcp/applications/semanticscholar/app.py +36 -78
  80. universal_mcp/applications/semrush/app.py +43 -77
  81. universal_mcp/applications/sendgrid/app.py +826 -1576
  82. universal_mcp/applications/sentry/app.py +444 -1079
  83. universal_mcp/applications/serpapi/app.py +40 -143
  84. universal_mcp/applications/sharepoint/README.md +16 -14
  85. universal_mcp/applications/sharepoint/app.py +245 -154
  86. universal_mcp/applications/shopify/app.py +1743 -4479
  87. universal_mcp/applications/shortcut/app.py +272 -534
  88. universal_mcp/applications/slack/app.py +58 -109
  89. universal_mcp/applications/spotify/app.py +206 -405
  90. universal_mcp/applications/supabase/app.py +174 -283
  91. universal_mcp/applications/tavily/app.py +2 -2
  92. universal_mcp/applications/trello/app.py +853 -2816
  93. universal_mcp/applications/twilio/app.py +14 -50
  94. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  95. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  96. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  97. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  98. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  99. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  100. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  101. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  102. universal_mcp/applications/whatsapp/app.py +35 -186
  103. universal_mcp/applications/whatsapp/audio.py +2 -6
  104. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  105. universal_mcp/applications/whatsapp_business/app.py +86 -299
  106. universal_mcp/applications/wrike/app.py +80 -153
  107. universal_mcp/applications/yahoo_finance/app.py +19 -65
  108. universal_mcp/applications/youtube/app.py +120 -306
  109. universal_mcp/applications/zenquotes/app.py +4 -4
  110. {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/METADATA +4 -2
  111. {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/RECORD +113 -117
  112. {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/WHEEL +1 -1
  113. universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
  114. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
  115. universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
  116. universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
  117. universal_mcp/applications/unipile/README.md +0 -28
  118. universal_mcp/applications/unipile/__init__.py +0 -1
  119. universal_mcp/applications/unipile/app.py +0 -1077
  120. {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,4 @@
1
1
  from typing import Any
2
-
3
2
  from universal_mcp.applications.application import APIApplication
4
3
  from universal_mcp.integrations import Integration
5
4
 
@@ -9,42 +8,44 @@ class GoogleDocsApp(APIApplication):
9
8
  super().__init__(name="google_docs", integration=integration)
10
9
  self.base_api_url = "https://docs.googleapis.com/v1/documents"
11
10
 
12
- def create_document(self, title: str) -> dict[str, Any]:
11
+ async def create_document(self, title: str) -> dict[str, Any]:
13
12
  """
14
- Creates a blank Google Document with a specified title using a POST request to the Google Docs API. This is the primary creation method, returning the document's metadata, including the ID required by functions like `get_document` or `insert_text` to perform subsequent operations on the new file.
13
+ Creates a blank Google Document with a specified title by sending a POST request to the Google Docs API. The function returns a dictionary containing the new document's metadata, including the unique document ID required by other functions for subsequent modifications or retrieval. Note that you need to call other google_docs functions (e.g. `google_docs__insert_text`) to actually add content after creating the document.
15
14
 
16
15
  Args:
17
- title: The title for the new Google Document to be created
16
+ title: The title for the new Google Document to be created.
18
17
 
19
18
  Returns:
20
- A dictionary containing the Google Docs API response with document details and metadata
19
+ A dictionary containing the response from the Google Docs API with document details and metadata.
21
20
 
22
21
  Raises:
23
- HTTPError: If the API request fails due to network issues, authentication errors, or invalid parameters
24
- RequestException: If there are connection errors or timeout issues during the API request
22
+ HTTPError: If the API request fails due to network issues, authentication errors, or invalid parameters.
23
+ RequestException: If there are connection errors or timeout issues during the API request.
25
24
 
26
25
  Tags:
27
26
  create, document, api, important, google-docs, http
28
27
  """
29
28
  url = self.base_api_url
30
29
  document_data = {"title": title}
31
- response = self._post(url, data=document_data)
30
+ response = await self._apost(url, data=document_data)
32
31
  response.raise_for_status()
33
- return response.json()
32
+ payload = response.json()
33
+ payload["Note"] = "You must load and call other google docs content functions (like google_docs__insert_text)"
34
+ return payload
34
35
 
35
36
  def get_document(self, document_id: str) -> dict[str, Any]:
36
37
  """
37
- Retrieves the complete content and metadata for a specific Google Document using its unique ID. This function performs a GET request to the API, returning the full JSON response. It's the primary read operation, contrasting with `create_document` which creates new documents.
38
+ Retrieves the complete, raw JSON object for a Google Document by its ID. This function returns the full, unprocessed API response with all metadata and structural elements, distinguishing it from `get_document_content`, which parses this data to extract only the title and plain text.
38
39
 
39
40
  Args:
40
- document_id: The unique identifier of the document to retrieve
41
+ document_id: The unique identifier of the Google Document to retrieve.
41
42
 
42
43
  Returns:
43
- A dictionary containing the document data from the Google Docs API response
44
+ A dictionary containing the complete document data as returned by the Google Docs API.
44
45
 
45
46
  Raises:
46
- HTTPError: If the API request fails or the document is not found
47
- JSONDecodeError: If the API response cannot be parsed as JSON
47
+ HTTPError: If the API request fails or the specified document cannot be found.
48
+ JSONDecodeError: If the API response is not valid JSON and cannot be parsed.
48
49
 
49
50
  Tags:
50
51
  retrieve, read, api, document, google-docs, important
@@ -53,38 +54,182 @@ class GoogleDocsApp(APIApplication):
53
54
  response = self._get(url)
54
55
  return response.json()
55
56
 
56
- def insert_text(
57
- self, document_id: str, content: str, index: int = 1
58
- ) -> dict[str, Any]:
57
+ async def get_document_content(self, document_id: str) -> dict[str, Any]:
59
58
  """
60
- Inserts a text string at a specified index within an existing Google Document using the `batchUpdate` API. This function adds new textual content, distinguishing it from functions that insert non-text elements like tables or apply formatting (`apply_text_style`) to existing content.
59
+ Retrieves and converts a Google Docs document into Markdown-formatted content.
60
+
61
+ This method calls the Google Docs API via `get_document`, then parses the document structure
62
+ to extract paragraphs, headings, lists, tables, images, equations, footnotes, and horizontal rules.
63
+ The final result is a clean Markdown string that closely mirrors the layout and content of
64
+ the original document, including support for nested lists and multi-row tables.
61
65
 
62
66
  Args:
63
- document_id: The unique identifier of the Google Document to be updated
64
- content: The text content to be inserted into the document
65
- index: The zero-based position in the document where the text should be inserted (default: 1)
67
+ document_id (str): The unique ID of the Google Document to retrieve.
66
68
 
67
69
  Returns:
68
- A dictionary containing the Google Docs API response after performing the batch update operation
70
+ dict[str, Any]: A dictionary with the following keys:
71
+ - 'title' (str): The document's title.
72
+ - 'content' (str): The document content converted to Markdown.
73
+ Markdown Output Supports:
74
+ - Paragraphs and line breaks
75
+ - Headings (Heading 1-6)
76
+ - Bulleted and numbered lists (with nesting)
77
+ - Tables (converted to Markdown tables)
78
+ - Inline images (`![](URL)` format)
79
+ - Equations (LaTeX-style `$...$`)
80
+ - Footnotes (`[^1]` references and notes at the end)
81
+ - Horizontal rules (`---`)
82
+
83
+ Tags:
84
+ google-docs, markdown, document-parsing, text-extraction, conversion, structured-data
85
+ """
86
+ import re
87
+
88
+ response = self.get_document(document_id)
89
+ title = response.get("title", "")
90
+ body_content = response.get("body", {}).get("content", [])
91
+ inline_objects = response.get("inlineObjects", {})
92
+ lists = response.get("lists", {})
93
+ footnotes_data = response.get("footnotes", {})
94
+ text_chunks: list[str] = []
95
+ footnotes: dict[str, str] = {}
96
+ footnote_index: dict[str, int] = {}
97
+ current_list_counters: dict[str, int] = {}
98
+
99
+ def extract_text_from_paragraph(paragraph: dict) -> str:
100
+ """Extracts paragraph text with inline formatting."""
101
+ text = ""
102
+ for elem in paragraph.get("elements", []):
103
+ if "textRun" in elem:
104
+ content = elem["textRun"].get("content", "")
105
+ text += content
106
+ elif "inlineObjectElement" in elem:
107
+ obj_id = elem["inlineObjectElement"]["inlineObjectId"]
108
+ obj = inline_objects.get(obj_id, {})
109
+ embed = obj.get("inlineObjectProperties", {}).get("embeddedObject", {})
110
+ image_source = embed.get("imageProperties", {}).get("contentUri", "")
111
+ if image_source:
112
+ text += f"\n\n![]({image_source})\n\n"
113
+ return text
114
+
115
+ def extract_table(table: dict) -> str:
116
+ rows = []
117
+ for i, row in enumerate(table.get("tableRows", [])):
118
+ cells = []
119
+ for cell in row.get("tableCells", []):
120
+ cell_text = ""
121
+ for content in cell.get("content", []):
122
+ if "paragraph" in content:
123
+ cell_text += extract_text_from_paragraph(content["paragraph"]).strip()
124
+ cells.append(cell_text)
125
+ row_line = "| " + " | ".join(cells) + " |"
126
+ rows.append(row_line)
127
+ if i == 0:
128
+ rows.insert(1, "| " + " | ".join(["---"] * len(cells)) + " |")
129
+ return "\n".join(rows)
130
+
131
+ def extract_heading_style(paragraph: dict) -> str:
132
+ """Returns appropriate Markdown heading level."""
133
+ style = paragraph.get("paragraphStyle", {})
134
+ heading = style.get("namedStyleType", "")
135
+ match = re.match("HEADING_(\\d)", heading)
136
+ if match:
137
+ level = int(match.group(1))
138
+ return "#" * level
139
+ return ""
140
+
141
+ def extract_list_prefix(paragraph: dict) -> str:
142
+ """Generates proper list prefix (numbered or bullet)."""
143
+ list_id = paragraph.get("bullet", {}).get("listId")
144
+ if not list_id:
145
+ return ""
146
+ glyph = paragraph["bullet"].get("glyph", None)
147
+ nesting = paragraph["bullet"].get("nestingLevel", 0)
148
+ list_info = lists.get(list_id, {})
149
+ list_type = list_info.get("listProperties", {}).get("nestingLevels", [{}])[nesting].get("glyphType")
150
+ indent = " " * nesting
151
+ if list_type and "DECIMAL" in list_type:
152
+ current_list_counters[list_id] = current_list_counters.get(list_id, 1)
153
+ prefix = f"{current_list_counters[list_id]}. "
154
+ current_list_counters[list_id] += 1
155
+ else:
156
+ prefix = "- "
157
+ return indent + prefix
158
+
159
+ def extract_equation(paragraph: dict) -> str:
160
+ return "\n\n$" + paragraph.get("equation", {}).get("equation", "") + "$\n\n"
161
+
162
+ def extract_footnote_ref(footnote_id: str) -> str:
163
+ if footnote_id not in footnote_index:
164
+ footnote_index[footnote_id] = len(footnotes) + 1
165
+ fn_content = footnotes_data.get(footnote_id, {}).get("content", [])
166
+ fn_text = ""
167
+ for item in fn_content:
168
+ if "paragraph" in item:
169
+ fn_text += extract_text_from_paragraph(item["paragraph"]).strip()
170
+ footnotes[footnote_id] = fn_text
171
+ return f"[^{footnote_index[footnote_id]}]"
172
+
173
+ for element in body_content:
174
+ if "paragraph" in element:
175
+ para = element["paragraph"]
176
+ if "equation" in para:
177
+ text_chunks.append(extract_equation(para))
178
+ continue
179
+ heading_md = extract_heading_style(para)
180
+ list_prefix = extract_list_prefix(para)
181
+ para_text = extract_text_from_paragraph(para).strip()
182
+ if para_text:
183
+ if heading_md:
184
+ text_chunks.append(f"{heading_md} {para_text}")
185
+ elif list_prefix:
186
+ text_chunks.append(f"{list_prefix}{para_text}")
187
+ else:
188
+ text_chunks.append(para_text)
189
+ elif "table" in element:
190
+ table_md = extract_table(element["table"])
191
+ text_chunks.append(table_md)
192
+ elif "horizontalRule" in element:
193
+ text_chunks.append("\n---\n")
194
+ elif "tableOfContents" in element:
195
+ text_chunks.append("<!-- Table of Contents -->")
196
+ elif "footnoteReference" in element:
197
+ footnote_id = element["footnoteReference"]["footnoteId"]
198
+ ref = extract_footnote_ref(footnote_id)
199
+ text_chunks.append(ref)
200
+ if footnotes:
201
+ text_chunks.append("\n## Footnotes\n")
202
+ for fid, index in sorted(footnote_index.items(), key=lambda x: x[1]):
203
+ text_chunks.append(f"[^{index}]: {footnotes[fid]}")
204
+ content = "\n\n".join((chunk.strip() for chunk in text_chunks if chunk.strip()))
205
+ return {"title": title, "content": content}
206
+
207
+ async def insert_text(self, document_id: str, content: str, index: int = 1) -> dict[str, Any]:
208
+ """
209
+ Inserts a text string at a specified index within a Google Document using the batchUpdate API. Unlike functions that format existing text or delete content ranges, this method specifically adds new textual content to the document body.
210
+
211
+ Args:
212
+ document_id: The unique identifier of the Google Document to be updated.
213
+ content: The text content to be inserted into the document.
214
+ index: The zero-based position in the document where the text should be inserted (default is 1).
215
+
216
+ Returns:
217
+ A dictionary containing the Google Docs API response after performing the batch update operation.
69
218
 
70
219
  Raises:
71
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
72
- RequestException: When there are network connectivity issues or API endpoint problems
220
+ HTTPError: If the API request fails, for example due to invalid document_id or insufficient permissions.
221
+ RequestException: If there are network connectivity issues or problems contacting the API endpoint.
73
222
 
74
223
  Tags:
75
224
  update, insert, document, api, google-docs, batch, content-management, important
76
225
  """
77
226
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
78
- batch_update_data = {
79
- "requests": [
80
- {"insertText": {"location": {"index": index}, "text": content}}
81
- ]
82
- }
83
- response = self._post(url, data=batch_update_data)
227
+ batch_update_data = {"requests": [{"insertText": {"location": {"index": index}, "text": content}}]}
228
+ response = await self._apost(url, data=batch_update_data)
84
229
  response.raise_for_status()
85
230
  return response.json()
86
231
 
87
- def apply_text_style(
232
+ async def apply_text_style(
88
233
  self,
89
234
  document_id: str,
90
235
  start_index: int,
@@ -98,56 +243,48 @@ class GoogleDocsApp(APIApplication):
98
243
  background_color: dict[str, float] | None = None,
99
244
  ) -> dict[str, Any]:
100
245
  """
101
- Applies character-level formatting such as bold, italic, font size, color, and hyperlinks to a specified text range in a document. This function modifies text appearance, distinguishing it from `update_paragraph_style`, which handles block-level formatting like alignment and headings.
246
+ Applies character-level formatting (e.g., bold, italic, color, links) to a specified text range. This function modifies text attributes directly, distinguishing it from `update_paragraph_style` which handles block-level properties like alignment.
102
247
 
103
248
  Args:
104
- document_id: The unique identifier of the Google Document to be updated
105
- start_index: The zero-based start index of the text range to style
106
- end_index: The zero-based end index of the text range to style (exclusive)
107
- bold: Whether the text should be bold
108
- italic: Whether the text should be italicized
109
- underline: Whether the text should be underlined
110
- font_size: The font size in points (e.g., 12.0 for 12pt)
111
- link_url: URL to make the text a hyperlink
112
- foreground_color: RGB color dict with 'red', 'green', 'blue' values (0.0 to 1.0)
113
- background_color: RGB color dict with 'red', 'green', 'blue' values (0.0 to 1.0)
249
+ document_id: The unique identifier of the Google Document to update.
250
+ start_index: The zero-based start index of the text range to apply the style.
251
+ end_index: The zero-based end index (exclusive) of the text range to apply the style.
252
+ bold: Whether to apply bold formatting to the text.
253
+ italic: Whether to apply italic formatting to the text.
254
+ underline: Whether to apply underline formatting to the text.
255
+ font_size: Font size in points (e.g., 12.0 for 12pt) to apply to the text.
256
+ link_url: URL to apply as a hyperlink to the text.
257
+ foreground_color: RGB color dictionary with 'red', 'green', and 'blue' floats (0.0 to 1.0) for the text color.
258
+ background_color: RGB color dictionary with 'red', 'green', and 'blue' floats (0.0 to 1.0) for the text background color.
114
259
 
115
260
  Returns:
116
- A dictionary containing the Google Docs API response
261
+ A dictionary containing the Google Docs API response, or a message if no styling was applied.
117
262
 
118
263
  Raises:
119
- HTTPError: When the API request fails
120
- RequestException: When there are network connectivity issues
264
+ HTTPError: If the Google Docs API request fails.
265
+ RequestException: If there are network connectivity issues during the API request.
121
266
 
122
267
  Tags:
123
- style, format, text, document, api, google-docs, simple
268
+ style, format, text, document, api, google-docs, important
124
269
  """
125
270
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
126
-
127
- # Build the text style object with only common properties
128
271
  text_style = {}
129
272
  fields_to_update = []
130
-
131
273
  if bold:
132
274
  text_style["bold"] = True
133
275
  fields_to_update.append("bold")
134
-
135
276
  if italic:
136
277
  text_style["italic"] = True
137
278
  fields_to_update.append("italic")
138
-
139
279
  if underline:
140
280
  text_style["underline"] = True
141
281
  fields_to_update.append("underline")
142
-
143
282
  if font_size is not None:
144
283
  text_style["fontSize"] = {"magnitude": font_size, "unit": "PT"}
145
284
  fields_to_update.append("fontSize")
146
-
147
285
  if link_url is not None:
148
286
  text_style["link"] = {"url": link_url}
149
287
  fields_to_update.append("link")
150
-
151
288
  if foreground_color is not None:
152
289
  text_style["foregroundColor"] = {
153
290
  "color": {
@@ -159,7 +296,6 @@ class GoogleDocsApp(APIApplication):
159
296
  }
160
297
  }
161
298
  fields_to_update.append("foregroundColor")
162
-
163
299
  if background_color is not None:
164
300
  text_style["backgroundColor"] = {
165
301
  "color": {
@@ -171,11 +307,8 @@ class GoogleDocsApp(APIApplication):
171
307
  }
172
308
  }
173
309
  fields_to_update.append("backgroundColor")
174
-
175
- # If no styling requested, return early
176
310
  if not text_style:
177
311
  return {"message": "No styling applied"}
178
-
179
312
  batch_update_data = {
180
313
  "requests": [
181
314
  {
@@ -187,11 +320,10 @@ class GoogleDocsApp(APIApplication):
187
320
  }
188
321
  ]
189
322
  }
190
-
191
- response = self._post(url, data=batch_update_data)
323
+ response = await self._apost(url, data=batch_update_data)
192
324
  return self._handle_response(response)
193
325
 
194
- def update_paragraph_style(
326
+ async def update_paragraph_style(
195
327
  self,
196
328
  document_id: str,
197
329
  start_index: int,
@@ -204,184 +336,127 @@ class GoogleDocsApp(APIApplication):
204
336
  tab_id: str | None = None,
205
337
  ) -> dict[str, Any]:
206
338
  """
207
- Applies paragraph-level formatting, such as named styles (e.g., 'HEADING_1'), alignment, or text direction, to a specified text range. This function handles block-level styles, distinguishing it from `apply_text_style`, which formats individual characters with attributes like bold or italic.
339
+ Applies paragraph-level formatting like alignment, named styles (e.g., 'HEADING_1'), and text direction to a text range in a Google Doc. Distinct from `apply_text_style`, which handles character formatting, this method modifies properties for entire paragraphs using the batchUpdate API.
208
340
 
209
341
  Args:
210
- document_id: The unique identifier of the Google Document to be updated
211
- start_index: The zero-based start index of the paragraph range to style
212
- end_index: The zero-based end index of the paragraph range to style (exclusive)
213
- named_style_type: The named style type (e.g., 'NORMAL_TEXT', 'TITLE', 'HEADING_1', etc.)
214
- alignment: The paragraph alignment ('START', 'CENTER', 'END', 'JUSTIFIED')
215
- direction: The content direction ('LEFT_TO_RIGHT', 'RIGHT_TO_LEFT')
216
- spacing_mode: The spacing mode ('NEVER_COLLAPSE', 'COLLAPSE_LISTS')
217
- segment_id: The segment ID for the range (optional)
218
- tab_id: The tab ID for the range (optional)
342
+ document_id: The unique identifier of the Google Document to update.
343
+ start_index: The zero-based start index of the paragraph range to style.
344
+ end_index: The zero-based end index of the paragraph range to style (exclusive).
345
+ named_style_type: The named style type to apply (e.g., 'NORMAL_TEXT', 'TITLE', 'HEADING_1').
346
+ alignment: Paragraph alignment option ('START', 'CENTER', 'END', 'JUSTIFIED').
347
+ direction: Content direction of the paragraph ('LEFT_TO_RIGHT', 'RIGHT_TO_LEFT').
348
+ spacing_mode: Spacing mode for the paragraph ('NEVER_COLLAPSE', 'COLLAPSE_LISTS').
349
+ segment_id: Optional segment ID for the text range.
350
+ tab_id: Optional tab ID for the text range.
219
351
 
220
352
  Returns:
221
- A dictionary containing the Google Docs API response
353
+ A dictionary containing the API response from the Google Docs batchUpdate request.
222
354
 
223
355
  Raises:
224
- HTTPError: When the API request fails
225
- RequestException: When there are network connectivity issues
356
+ HTTPError: If the API request to update the document fails due to an HTTP error.
357
+ RequestException: If there are network connectivity issues during the API request.
226
358
 
227
359
  Tags:
228
- style, format, paragraph, document, api, google-docs, batch, content-management
360
+ style, format, paragraph, document, api, google-docs, batch, content-management, important
229
361
  """
230
362
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
231
-
232
- # Build the paragraph style object with only specified properties
233
363
  paragraph_style = {}
234
364
  fields_to_update = []
235
-
236
365
  if named_style_type is not None:
237
366
  paragraph_style["namedStyleType"] = named_style_type
238
367
  fields_to_update.append("namedStyleType")
239
-
240
368
  if alignment is not None:
241
369
  paragraph_style["alignment"] = alignment
242
370
  fields_to_update.append("alignment")
243
-
244
371
  if direction is not None:
245
372
  paragraph_style["direction"] = direction
246
373
  fields_to_update.append("direction")
247
-
248
374
  if spacing_mode is not None:
249
375
  paragraph_style["spacingMode"] = spacing_mode
250
376
  fields_to_update.append("spacingMode")
251
-
252
- # If no styling requested, return early
253
377
  if not paragraph_style:
254
378
  return {"message": "No paragraph styling applied"}
255
-
256
- # Build the range object
257
379
  range_obj: dict[str, Any] = {"startIndex": start_index, "endIndex": end_index}
258
-
259
- # Add optional parameters if provided
260
380
  if segment_id is not None:
261
381
  range_obj["segmentId"] = segment_id
262
382
  if tab_id is not None:
263
383
  range_obj["tabId"] = tab_id
264
-
265
384
  batch_update_data = {
266
385
  "requests": [
267
- {
268
- "updateParagraphStyle": {
269
- "range": range_obj,
270
- "paragraphStyle": paragraph_style,
271
- "fields": ",".join(fields_to_update),
272
- }
273
- }
386
+ {"updateParagraphStyle": {"range": range_obj, "paragraphStyle": paragraph_style, "fields": ",".join(fields_to_update)}}
274
387
  ]
275
388
  }
276
-
277
- response = self._post(url, data=batch_update_data)
389
+ response = await self._apost(url, data=batch_update_data)
278
390
  return self._handle_response(response)
279
391
 
280
- def delete_content_range(
281
- self,
282
- document_id: str,
283
- start_index: int,
284
- end_index: int,
285
- segment_id: str | None = None,
286
- tab_id: str | None = None,
392
+ async def delete_content_range(
393
+ self, document_id: str, start_index: int, end_index: int, segment_id: str | None = None, tab_id: str | None = None
287
394
  ) -> dict[str, Any]:
288
395
  """
289
- Deletes content within a specified index range in a Google Document via the batchUpdate API. It removes any content based on location, distinguishing it from functions like `delete_header` or `delete_paragraph_bullets`, which remove specific structures or styles instead.
396
+ Removes content from a specified index range in a Google Document via the batchUpdate API. Unlike functions that delete entire elements (e.g., `delete_header`), this provides granular control by targeting content based on its precise start and end location, optionally within a specific segment or tab.
290
397
 
291
398
  Args:
292
- document_id: The unique identifier of the Google Document to be updated
293
- start_index: The zero-based start index of the content range to delete
294
- end_index: The zero-based end index of the content range to delete (exclusive)
295
- segment_id: The ID of the header, footer, or footnote segment (optional)
296
- tab_id: The ID of the tab containing the content to delete (optional)
399
+ document_id: The unique identifier of the Google Document to be updated.
400
+ start_index: The zero-based start index of the content range to delete.
401
+ end_index: The zero-based end index of the content range to delete (exclusive).
402
+ segment_id: Optional; the ID of the header, footer, or footnote segment containing the content.
403
+ tab_id: Optional; the ID of the tab containing the content to delete.
297
404
 
298
405
  Returns:
299
- A dictionary containing the Google Docs API response after performing the delete operation
406
+ A dictionary representing the Google Docs API response after performing the delete operation.
300
407
 
301
408
  Raises:
302
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
303
- RequestException: When there are network connectivity issues or API endpoint problems
409
+ HTTPError: Raised when the API request fails due to issues such as invalid document ID or insufficient permissions.
410
+ RequestException: Raised when there are network connectivity issues or problems with the API endpoint.
304
411
 
305
412
  Tags:
306
413
  delete, remove, content, document, api, google-docs, batch, content-management, important
307
414
  """
308
415
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
309
-
310
- # Build the delete content range request
311
- delete_request: dict[str, Any] = {
312
- "range": {"startIndex": start_index, "endIndex": end_index}
313
- }
314
-
315
- # Add optional parameters if provided
416
+ delete_request: dict[str, Any] = {"range": {"startIndex": start_index, "endIndex": end_index}}
316
417
  if segment_id is not None:
317
418
  delete_request["range"]["segmentId"] = segment_id
318
419
  if tab_id is not None:
319
420
  delete_request["tabId"] = tab_id
320
-
321
421
  batch_update_data = {"requests": [{"deleteContentRange": delete_request}]}
322
-
323
- response = self._post(url, data=batch_update_data)
422
+ response = await self._apost(url, data=batch_update_data)
324
423
  return self._handle_response(response)
325
424
 
326
- def insert_table(
327
- self,
328
- document_id: str,
329
- location_index: int,
330
- rows: int,
331
- columns: int,
332
- segment_id: str = None,
333
- tab_id: str = None,
425
+ async def insert_table(
426
+ self, document_id: str, location_index: int, rows: int, columns: int, segment_id: str = None, tab_id: str = None
334
427
  ) -> dict[str, Any]:
335
428
  """
336
- Inserts a table with specified row and column dimensions at a given index in a Google Document. This function uses the `batchUpdate` API for precise placement, allowing the table to be added to the document's body, a header, or a footer, returning the API's response.
429
+ Inserts a table with specified rows and columns at a given index in a Google Document using the batchUpdate API. It can optionally place the table within specific document segments, such as headers or footers, handling structural additions rather than text or style modifications.
337
430
 
338
431
  Args:
339
- document_id: The unique identifier of the Google Document to be updated
340
- location_index: The zero-based index where the table should be inserted
341
- rows: The number of rows in the table
342
- columns: The number of columns in the table
343
- segment_id: The ID of the header, footer or footnote segment (optional)
344
- tab_id: The ID of the tab containing the location (optional)
432
+ document_id: The unique identifier of the Google Document to be updated.
433
+ location_index: The zero-based index within the document body or segment where the table should be inserted.
434
+ rows: The number of rows the inserted table should have.
435
+ columns: The number of columns the inserted table should have.
436
+ segment_id: Optional ID of the header, footer, or footnote segment where the table will be inserted (if applicable).
437
+ tab_id: Optional ID of the tab containing the insertion location.
345
438
 
346
439
  Returns:
347
- A dictionary containing the Google Docs API response after performing the insert table operation
440
+ A dictionary containing the response from the Google Docs API after performing the table insertion.
348
441
 
349
442
  Raises:
350
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
351
- RequestException: When there are network connectivity issues or API endpoint problems
443
+ HTTPError: Raised when the API request fails due to reasons such as invalid document ID or insufficient permissions.
444
+ RequestException: Raised when there are network connectivity issues or problems reaching the API endpoint.
352
445
 
353
446
  Tags:
354
- table, insert, document, api, google-docs, batch, content-management
447
+ table, insert, document, api, google-docs, batch, content-management, important
355
448
  """
356
449
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
357
-
358
- # Build the location object according to Google Docs API specification
359
450
  location = {"index": location_index}
360
-
361
- # Add segment_id if provided (empty string for document body, specific ID for header/footer/footnote)
362
451
  if segment_id is not None:
363
452
  location["segmentId"] = segment_id
364
-
365
- # Add tab_id if provided
366
453
  if tab_id is not None:
367
454
  location["tabId"] = tab_id
368
-
369
- batch_update_data = {
370
- "requests": [
371
- {
372
- "insertTable": {
373
- "location": location,
374
- "rows": rows,
375
- "columns": columns,
376
- }
377
- }
378
- ]
379
- }
380
-
381
- response = self._post(url, data=batch_update_data)
455
+ batch_update_data = {"requests": [{"insertTable": {"location": location, "rows": rows, "columns": columns}}]}
456
+ response = await self._apost(url, data=batch_update_data)
382
457
  return self._handle_response(response)
383
458
 
384
- def create_footer(
459
+ async def create_footer(
385
460
  self,
386
461
  document_id: str,
387
462
  footer_type: str = "DEFAULT",
@@ -390,48 +465,39 @@ class GoogleDocsApp(APIApplication):
390
465
  section_break_tab_id: str = None,
391
466
  ) -> dict[str, Any]:
392
467
  """
393
- Creates a footer of a specified type in a Google Document via the batch update API. The footer can optionally be associated with a specific section break, enabling distinct footers for different document sections, distinguishing it from the `create_header` and `create_footnote` functions.
468
+ Creates a footer of a specified type in a Google Document using the batch update API. This function, distinct from `create_header`, can optionally associate the new footer with a specific section break, enabling section-specific footers within the document.
394
469
 
395
470
  Args:
396
- document_id: The unique identifier of the Google Document to be updated
397
- footer_type: The type of footer to create (DEFAULT, HEADER_FOOTER_TYPE_UNSPECIFIED)
398
- section_break_location_index: The index of the SectionBreak location (optional)
399
- section_break_segment_id: The segment ID of the SectionBreak location (optional)
400
- section_break_tab_id: The tab ID of the SectionBreak location (optional)
471
+ document_id: The unique identifier of the Google Document to update.
472
+ footer_type: The type of footer to create, such as 'DEFAULT' or 'HEADER_FOOTER_TYPE_UNSPECIFIED'.
473
+ section_break_location_index: Optional index of the SectionBreak location to associate with the footer.
474
+ section_break_segment_id: Optional segment ID of the SectionBreak location.
475
+ section_break_tab_id: Optional tab ID of the SectionBreak location.
401
476
 
402
477
  Returns:
403
- A dictionary containing the Google Docs API response after performing the create footer operation
478
+ A dictionary containing the Google Docs API response from the create footer operation.
404
479
 
405
480
  Raises:
406
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
407
- RequestException: When there are network connectivity issues or API endpoint problems
481
+ HTTPError: Raised when the API request fails due to reasons like invalid document_id or insufficient permissions.
482
+ RequestException: Raised when there are network connectivity issues or problems with the API endpoint.
408
483
 
409
484
  Tags:
410
- footer, create, document, api, google-docs, batch, content-management
485
+ footer, create, document, api, google-docs, batch, content-management, important
411
486
  """
412
487
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
413
-
414
- # Build the create footer request
415
488
  create_footer_request = {"type": footer_type}
416
-
417
- # Add section break location if provided
418
489
  if section_break_location_index is not None:
419
490
  section_break_location = {"index": section_break_location_index}
420
-
421
491
  if section_break_segment_id is not None:
422
492
  section_break_location["segmentId"] = section_break_segment_id
423
-
424
493
  if section_break_tab_id is not None:
425
494
  section_break_location["tabId"] = section_break_tab_id
426
-
427
495
  create_footer_request["sectionBreakLocation"] = section_break_location
428
-
429
496
  batch_update_data = {"requests": [{"createFooter": create_footer_request}]}
430
-
431
- response = self._post(url, data=batch_update_data)
497
+ response = await self._apost(url, data=batch_update_data)
432
498
  return self._handle_response(response)
433
499
 
434
- def create_footnote(
500
+ async def create_footnote(
435
501
  self,
436
502
  document_id: str,
437
503
  location_index: int = None,
@@ -442,101 +508,75 @@ class GoogleDocsApp(APIApplication):
442
508
  end_of_segment_tab_id: str = None,
443
509
  ) -> dict[str, Any]:
444
510
  """
445
- Creates a footnote via the batch update API, inserting a numbered reference at a specified index or a segment's end. This function adds an in-body citation, distinguishing it from `create_footer` which creates a content block at the bottom of the page.
511
+ Inserts a numbered footnote reference into a Google Document using the batchUpdate API. The footnote can be placed at a precise index or at the end of a document segment, distinct from the `create_footer` function which adds standard page footers.
446
512
 
447
513
  Args:
448
- document_id: The unique identifier of the Google Document to be updated
449
- location_index: The index where to insert the footnote reference (optional)
450
- location_segment_id: The segment ID for the location (optional, must be empty for body)
451
- location_tab_id: The tab ID for the location (optional)
452
- end_of_segment_location: Whether to insert at end of segment (optional)
453
- end_of_segment_segment_id: The segment ID for end of segment location (optional)
454
- end_of_segment_tab_id: The tab ID for end of segment location (optional)
514
+ document_id: The unique identifier of the Google Document to be updated.
515
+ location_index: The zero-based index within the document where the footnote reference will be inserted (optional if inserting at end of segment).
516
+ location_segment_id: The segment ID where the footnote reference should be inserted (optional, usually empty for the document body).
517
+ location_tab_id: The tab ID for the location within the segment (optional).
518
+ end_of_segment_location: If True, inserts the footnote reference at the end of a segment instead of a specific index (default is False).
519
+ end_of_segment_segment_id: The segment ID indicating where to insert the footnote at the end of a segment (optional).
520
+ end_of_segment_tab_id: The tab ID for the end-of-segment location (optional).
455
521
 
456
522
  Returns:
457
- A dictionary containing the Google Docs API response after performing the create footnote operation
523
+ A dictionary containing the response from the Google Docs API after performing the footnote creation operation.
458
524
 
459
525
  Raises:
460
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
461
- RequestException: When there are network connectivity issues or API endpoint problems
526
+ HTTPError: Raised when the API request fails, such as due to an invalid document ID or insufficient permissions.
527
+ RequestException: Raised when there are network connectivity issues or problems reaching the API endpoint.
462
528
 
463
529
  Tags:
464
- footnote, create, document, api, google-docs, batch, content-management
530
+ footnote, create, document, api, google-docs, batch, content-management, important
465
531
  """
466
532
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
467
-
468
- # Build the create footnote request
469
533
  create_footnote_request = {}
470
-
471
534
  if end_of_segment_location:
472
- # Use endOfSegmentLocation
473
535
  end_of_segment_location_obj = {}
474
-
475
536
  if end_of_segment_segment_id is not None:
476
537
  end_of_segment_location_obj["segmentId"] = end_of_segment_segment_id
477
-
478
538
  if end_of_segment_tab_id is not None:
479
539
  end_of_segment_location_obj["tabId"] = end_of_segment_tab_id
480
-
481
- create_footnote_request["endOfSegmentLocation"] = (
482
- end_of_segment_location_obj
483
- )
540
+ create_footnote_request["endOfSegmentLocation"] = end_of_segment_location_obj
484
541
  else:
485
- # Use specific location
486
542
  location = {"index": location_index}
487
-
488
543
  if location_segment_id is not None:
489
544
  location["segmentId"] = location_segment_id
490
-
491
545
  if location_tab_id is not None:
492
546
  location["tabId"] = location_tab_id
493
-
494
547
  create_footnote_request["location"] = location
495
-
496
548
  batch_update_data = {"requests": [{"createFootnote": create_footnote_request}]}
497
-
498
- response = self._post(url, data=batch_update_data)
549
+ response = await self._apost(url, data=batch_update_data)
499
550
  return self._handle_response(response)
500
551
 
501
- def delete_footer(
502
- self,
503
- document_id: str,
504
- footer_id: str,
505
- tab_id: str = None,
506
- ) -> dict[str, Any]:
552
+ async def delete_footer(self, document_id: str, footer_id: str, tab_id: str = None) -> dict[str, Any]:
507
553
  """
508
- Deletes a specific footer from a Google Document using its unique ID via a `batchUpdate` request. This operation, the counterpart to `create_footer`, removes an entire footer section, unlike `delete_content_range` which targets text within a specified index range.
554
+ Deletes a specific footer from a Google Document using its unique ID via a batchUpdate API request. This operation removes the entire footer object, optionally within a specific tab, distinguishing it from functions that delete headers (`delete_header`) or general content (`delete_content_range`).
509
555
 
510
556
  Args:
511
- document_id: The unique identifier of the Google Document to be updated
512
- footer_id: The ID of the footer to delete
513
- tab_id: The tab that contains the footer to delete (optional)
557
+ document_id: The unique identifier of the Google Document to be updated.
558
+ footer_id: The identifier of the footer to delete.
559
+ tab_id: Optional identifier of the tab containing the footer to delete.
514
560
 
515
561
  Returns:
516
- A dictionary containing the Google Docs API response after performing the delete footer operation
562
+ A dictionary containing the response from the Google Docs API after performing the delete footer operation.
517
563
 
518
564
  Raises:
519
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
520
- RequestException: When there are network connectivity issues or API endpoint problems
565
+ HTTPError: Raised when the API request fails due to reasons such as an invalid document ID or insufficient permissions.
566
+ RequestException: Raised for network-related issues or problems reaching the API endpoint.
521
567
 
522
568
  Tags:
523
- footer, delete, remove, document, api, google-docs, batch, content-management
569
+ footer, delete, remove, document, api, google-docs, batch, content-management, important
524
570
  """
525
571
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
526
-
527
- # Build the delete footer request
528
572
  delete_footer_request = {"footerId": footer_id}
529
-
530
- # Add tab_id if provided
531
573
  if tab_id is not None:
532
574
  delete_footer_request["tabId"] = tab_id
533
-
534
575
  batch_update_data = {"requests": [{"deleteFooter": delete_footer_request}]}
535
-
536
- response = self._post(url, data=batch_update_data)
576
+ response = await self._apost(url, data=batch_update_data)
537
577
  return self._handle_response(response)
538
578
 
539
- def create_header(
579
+ async def create_header(
540
580
  self,
541
581
  document_id: str,
542
582
  header_type: str = "DEFAULT",
@@ -545,206 +585,136 @@ class GoogleDocsApp(APIApplication):
545
585
  section_break_tab_id: str = None,
546
586
  ) -> dict[str, Any]:
547
587
  """
548
- Creates a header in a specified Google Document via the batchUpdate API endpoint. This function allows defining the header type and can optionally associate it with a specific section break location. It complements the `delete_header` and `create_footer` functions for managing document structure.
588
+ Creates a header of a specified type in a Google Document using the batchUpdate API. This function can optionally associate the new header with a specific section break, distinguishing it from the `create_footer` method, which performs the equivalent action for footers.
549
589
 
550
590
  Args:
551
- document_id: The unique identifier of the Google Document to be updated
552
- header_type: The type of header to create (DEFAULT, HEADER_FOOTER_TYPE_UNSPECIFIED)
553
- section_break_location_index: The index of the SectionBreak location (optional)
554
- section_break_segment_id: The segment ID of the SectionBreak location (optional)
555
- section_break_tab_id: The tab ID of the SectionBreak location (optional)
591
+ document_id: The unique identifier of the Google Document to be updated.
592
+ header_type: The type of header to create, e.g., 'DEFAULT' or 'HEADER_FOOTER_TYPE_UNSPECIFIED'.
593
+ section_break_location_index: The index position of the section break location within the document, if applicable.
594
+ section_break_segment_id: The segment ID associated with the section break location, if applicable.
595
+ section_break_tab_id: The tab ID associated with the section break location, if applicable.
556
596
 
557
597
  Returns:
558
- A dictionary containing the Google Docs API response after performing the create header operation
598
+ A dictionary containing the response from the Google Docs API after the header creation request.
559
599
 
560
600
  Raises:
561
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
562
- RequestException: When there are network connectivity issues or API endpoint problems
601
+ HTTPError: If the API request fails due to issues such as an invalid document ID or insufficient permissions.
602
+ RequestException: If there are network problems or issues reaching the API endpoint.
563
603
 
564
604
  Tags:
565
605
  header, create, document, api, google-docs, batch, content-management, important
566
606
  """
567
607
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
568
-
569
- # Build the create header request
570
608
  create_header_request = {"type": header_type}
571
-
572
- # Add section break location if provided
573
609
  if section_break_location_index is not None:
574
610
  section_break_location = {"index": section_break_location_index}
575
-
576
611
  if section_break_segment_id is not None:
577
612
  section_break_location["segmentId"] = section_break_segment_id
578
-
579
613
  if section_break_tab_id is not None:
580
614
  section_break_location["tabId"] = section_break_tab_id
581
-
582
615
  create_header_request["sectionBreakLocation"] = section_break_location
583
-
584
616
  batch_update_data = {"requests": [{"createHeader": create_header_request}]}
585
-
586
- response = self._post(url, data=batch_update_data)
617
+ response = await self._apost(url, data=batch_update_data)
587
618
  return self._handle_response(response)
588
619
 
589
- def delete_header(
590
- self,
591
- document_id: str,
592
- header_id: str,
593
- tab_id: str = None,
594
- ) -> dict[str, Any]:
620
+ async def delete_header(self, document_id: str, header_id: str, tab_id: str = None) -> dict[str, Any]:
595
621
  """
596
- Removes a specific header from a Google Document using its unique ID. This function sends a `deleteHeader` request to the batch update API, acting as the direct counterpart to `create_header` and distinguishing it from `delete_footer` which removes footers.
622
+ Deletes a specific header from a Google Document using its unique ID via a batchUpdate API request. This function, the counterpart to `create_header`, removes headers and can optionally target a header within a specific tab. It requires both the document and header IDs for the operation.
597
623
 
598
624
  Args:
599
- document_id: The unique identifier of the Google Document to be updated
600
- header_id: The ID of the header to delete
601
- tab_id: The tab containing the header to delete (optional)
625
+ document_id: The unique identifier of the Google Document to be updated.
626
+ header_id: The ID of the header to delete.
627
+ tab_id: Optional ID of the tab containing the header to delete.
602
628
 
603
629
  Returns:
604
- A dictionary containing the Google Docs API response after performing the delete header operation
630
+ A dictionary containing the response from the Google Docs API after performing the delete header operation.
605
631
 
606
632
  Raises:
607
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
608
- RequestException: When there are network connectivity issues or API endpoint problems
633
+ HTTPError: Raised when the API request fails due to invalid document_id, insufficient permissions, or other HTTP errors.
634
+ RequestException: Raised when network connectivity issues or API endpoint problems occur during the request.
609
635
 
610
636
  Tags:
611
- header, delete, remove, document, api, google-docs, batch, content-management
637
+ header, delete, remove, document, api, google-docs, batch, content-management, important
612
638
  """
613
639
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
614
-
615
- # Build the delete header request
616
640
  delete_header_request = {"headerId": header_id}
617
-
618
- # Add tab_id if provided
619
641
  if tab_id is not None:
620
642
  delete_header_request["tabId"] = tab_id
621
-
622
643
  batch_update_data = {"requests": [{"deleteHeader": delete_header_request}]}
623
-
624
- response = self._post(url, data=batch_update_data)
644
+ response = await self._apost(url, data=batch_update_data)
625
645
  return self._handle_response(response)
626
646
 
627
- def apply_list_style(
628
- self,
629
- document_id: str,
630
- start_index: int,
631
- end_index: int,
632
- bullet_preset: str,
633
- segment_id: str = None,
634
- tab_id: str = None,
647
+ async def apply_list_style(
648
+ self, document_id: str, start_index: int, end_index: int, bullet_preset: str, segment_id: str = None, tab_id: str = None
635
649
  ) -> dict[str, Any]:
636
650
  """
637
- Applies a predefined bulleted or numbered list format to paragraphs within a specified range using a `bullet_preset`. This function adds list formatting, distinguishing it from its counterpart, `delete_paragraph_bullets`, and other styling functions like `update_paragraph_style`, which handles alignment and headings.
651
+ Applies a predefined list style (bulleted or numbered) to paragraphs within a specified range using a chosen preset. Unlike `delete_paragraph_bullets`, which removes list formatting, this function creates it, distinguishing it from other text and paragraph styling methods in the class.
638
652
 
639
653
  Args:
640
- document_id: The unique identifier of the Google Document to be updated
641
- start_index: The zero-based start index of the range to apply bullets to
642
- end_index: The zero-based end index of the range to apply bullets to (exclusive)
643
- bullet_preset: The kind of bullet glyphs to use. Available options:
644
- - BULLET_GLYPH_PRESET_UNSPECIFIED: The bullet glyph preset is unspecified
645
- - BULLET_DISC_CIRCLE_SQUARE: DISC, CIRCLE and SQUARE for first 3 nesting levels
646
- - BULLET_DIAMONDX_ARROW3D_SQUARE: DIAMONDX, ARROW3D and SQUARE for first 3 nesting levels
647
- - BULLET_CHECKBOX: CHECKBOX bullet glyphs for all nesting levels
648
- - BULLET_ARROW_DIAMOND_DISC: ARROW, DIAMOND and DISC for first 3 nesting levels
649
- - BULLET_STAR_CIRCLE_SQUARE: STAR, CIRCLE and SQUARE for first 3 nesting levels
650
- - BULLET_ARROW3D_CIRCLE_SQUARE: ARROW3D, CIRCLE and SQUARE for first 3 nesting levels
651
- - BULLET_LEFTTRIANGLE_DIAMOND_DISC: LEFTTRIANGLE, DIAMOND and DISC for first 3 nesting levels
652
- - BULLET_DIAMONDX_HOLLOWDIAMOND_SQUARE: DIAMONDX, HOLLOWDIAMOND and SQUARE for first 3 nesting levels
653
- - BULLET_DIAMOND_CIRCLE_SQUARE: DIAMOND, CIRCLE and SQUARE for first 3 nesting levels
654
- - NUMBERED_DECIMAL_ALPHA_ROMAN: DECIMAL, ALPHA and ROMAN with periods
655
- - NUMBERED_DECIMAL_ALPHA_ROMAN_PARENS: DECIMAL, ALPHA and ROMAN with parenthesis
656
- - NUMBERED_DECIMAL_NESTED: DECIMAL with nested numbering (1., 1.1., 2., 2.2.)
657
- - NUMBERED_UPPERALPHA_ALPHA_ROMAN: UPPERALPHA, ALPHA and ROMAN with periods
658
- - NUMBERED_UPPERROMAN_UPPERALPHA_DECIMAL: UPPERROMAN, UPPERALPHA and DECIMAL with periods
659
- - NUMBERED_ZERODECIMAL_ALPHA_ROMAN: ZERODECIMAL, ALPHA and ROMAN with periods
660
- segment_id: The segment ID for the range (optional)
661
- tab_id: The tab ID for the range (optional)
654
+ document_id: The unique identifier of the Google Document to be updated.
655
+ start_index: The zero-based start index of the text range to which the list style should be applied.
656
+ end_index: The zero-based end index (exclusive) of the text range to apply the list style.
657
+ bullet_preset: Specifies the bullet or numbering style preset to use (e.g., bulleted or numbered formats with specific glyphs).
658
+ segment_id: Optional segment ID within the document where the updates apply.
659
+ tab_id: Optional tab ID within the segment to narrow the update scope.
662
660
 
663
661
  Returns:
664
- A dictionary containing the Google Docs API response after performing the create bullets operation
662
+ A dictionary representing the Google Docs API response confirming the application of the bullet list style.
665
663
 
666
664
  Raises:
667
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
668
- RequestException: When there are network connectivity issues or API endpoint problems
665
+ HTTPError: Raised when the API request to update the document fails (e.g., invalid document ID or insufficient permissions).
666
+ RequestException: Raised on network issues or problems reaching the API endpoint.
669
667
 
670
668
  Tags:
671
- bullets, list, paragraph, document, api, google-docs, batch, content-management
669
+ bullets, list, paragraph, document, api, google-docs, batch, content-management, important
672
670
  """
673
671
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
674
-
675
- # Build the range object
676
672
  range_obj = {"startIndex": start_index, "endIndex": end_index}
677
-
678
- # Add optional parameters if provided
679
673
  if segment_id is not None:
680
674
  range_obj["segmentId"] = segment_id
681
675
  if tab_id is not None:
682
676
  range_obj["tabId"] = tab_id
683
-
684
- batch_update_data = {
685
- "requests": [
686
- {
687
- "createParagraphBullets": {
688
- "range": range_obj,
689
- "bulletPreset": bullet_preset,
690
- }
691
- }
692
- ]
693
- }
694
-
695
- response = self._post(url, data=batch_update_data)
677
+ batch_update_data = {"requests": [{"createParagraphBullets": {"range": range_obj, "bulletPreset": bullet_preset}}]}
678
+ response = await self._apost(url, data=batch_update_data)
696
679
  return self._handle_response(response)
697
680
 
698
- def delete_paragraph_bullets(
699
- self,
700
- document_id: str,
701
- start_index: int,
702
- end_index: int,
703
- segment_id: str = None,
704
- tab_id: str = None,
681
+ async def delete_paragraph_bullets(
682
+ self, document_id: str, start_index: int, end_index: int, segment_id: str = None, tab_id: str = None
705
683
  ) -> dict[str, Any]:
706
684
  """
707
- Removes bullet points or numbering from paragraphs within a specified range in a Google Document. This function reverts list formatting via the batch update API, acting as the direct counterpart to `apply_list_style` and preserving the underlying text content, unlike `delete_content_range`.
685
+ Removes bullet points or numbering from paragraphs within a specified index range in a Google Document. This reverts list formatting to normal text while preserving content, acting as the inverse operation to the `apply_list_style` function.
708
686
 
709
687
  Args:
710
- document_id: The unique identifier of the Google Document to be updated
711
- start_index: The zero-based start index of the range to remove bullets from
712
- end_index: The zero-based end index of the range to remove bullets from (exclusive)
713
- segment_id: The segment ID for the range (optional)
714
- tab_id: The tab ID for the range (optional)
688
+ document_id: The unique identifier of the Google Document to be updated.
689
+ start_index: The zero-based start index of the range to remove bullets from.
690
+ end_index: The zero-based end index of the range to remove bullets from (exclusive).
691
+ segment_id: Optional segment ID specifying a subset of the document where the range applies.
692
+ tab_id: Optional tab ID specifying a particular tab within the document where the range applies.
715
693
 
716
694
  Returns:
717
- A dictionary containing the Google Docs API response after performing the delete bullets operation
695
+ A dictionary containing the Google Docs API response after performing the delete bullets operation.
718
696
 
719
697
  Raises:
720
- HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
721
- RequestException: When there are network connectivity issues or API endpoint problems
698
+ HTTPError: Raised when the API request fails due to invalid document ID, insufficient permissions, or other server-side errors.
699
+ RequestException: Raised when there are network connectivity issues or problems accessing the API endpoint.
722
700
 
723
701
  Tags:
724
702
  bullets, delete, remove, list, paragraph, document, api, google-docs, batch, content-management
725
703
  """
726
704
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
727
-
728
- # Build the range object
729
705
  range_obj = {"startIndex": start_index, "endIndex": end_index}
730
-
731
- # Add optional parameters if provided
732
706
  if segment_id is not None:
733
707
  range_obj["segmentId"] = segment_id
734
708
  if tab_id is not None:
735
709
  range_obj["tabId"] = tab_id
736
-
737
- batch_update_data = {
738
- "requests": [{"deleteParagraphBullets": {"range": range_obj}}]
739
- }
740
-
741
- response = self._post(url, data=batch_update_data)
710
+ batch_update_data = {"requests": [{"deleteParagraphBullets": {"range": range_obj}}]}
711
+ response = await self._apost(url, data=batch_update_data)
742
712
  return self._handle_response(response)
743
713
 
744
714
  def list_tools(self):
745
715
  return [
746
716
  self.create_document,
747
- self.get_document,
717
+ self.get_document_content,
748
718
  self.insert_text,
749
719
  self.apply_text_style,
750
720
  self.delete_content_range,