arcade-google-docs 4.0.0__py3-none-any.whl → 4.1.0__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.
- arcade_google_docs/docmd.py +534 -0
- arcade_google_docs/enum.py +1 -0
- arcade_google_docs/models/document.py +953 -0
- arcade_google_docs/models/document_writables.py +735 -0
- arcade_google_docs/models/requests.py +1315 -0
- arcade_google_docs/tools/edit_agent/edit_agent.py +56 -0
- arcade_google_docs/tools/edit_agent/executor.py +103 -0
- arcade_google_docs/tools/edit_agent/models/planning.py +89 -0
- arcade_google_docs/tools/edit_agent/planner.py +130 -0
- arcade_google_docs/tools/edit_agent/progress_tracker.py +32 -0
- arcade_google_docs/tools/edit_agent/prompts.py +204 -0
- arcade_google_docs/tools/edit_agent/request_generator.py +150 -0
- arcade_google_docs/tools/edit_agent/utils.py +21 -0
- arcade_google_docs/tools/get.py +26 -0
- arcade_google_docs/tools/search.py +5 -1
- {arcade_google_docs-4.0.0.dist-info → arcade_google_docs-4.1.0.dist-info}/METADATA +2 -1
- arcade_google_docs-4.1.0.dist-info/RECORD +28 -0
- arcade_google_docs-4.0.0.dist-info/RECORD +0 -16
- {arcade_google_docs-4.0.0.dist-info → arcade_google_docs-4.1.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,1315 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Implements all resources used by the 'Request' resource.
|
|
3
|
+
The resources are defined at https://developers.google.com/workspace/docs/api/reference/rest/v1/documents/request
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from collections.abc import Callable
|
|
9
|
+
from enum import Enum
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, ConfigDict, Field, model_serializer
|
|
13
|
+
|
|
14
|
+
from arcade_google_docs.models.document import (
|
|
15
|
+
SectionType,
|
|
16
|
+
)
|
|
17
|
+
from arcade_google_docs.models.document_writables import (
|
|
18
|
+
DocumentStyleWritable,
|
|
19
|
+
ParagraphStyleWritable,
|
|
20
|
+
RangeWritable,
|
|
21
|
+
SectionStyleWritable,
|
|
22
|
+
SizeWritable,
|
|
23
|
+
TableCellStyleWritable,
|
|
24
|
+
TableColumnPropertiesWritable,
|
|
25
|
+
TableRowStyleWritable,
|
|
26
|
+
TextStyleWritable,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class EditRequestType(str, Enum):
|
|
31
|
+
"""Edit request types supported by the Google Docs batchUpdate endpoint.
|
|
32
|
+
|
|
33
|
+
Does not include the following edit requests:
|
|
34
|
+
- createHeader
|
|
35
|
+
- createFooter
|
|
36
|
+
- createFootnote
|
|
37
|
+
- createNamedRange
|
|
38
|
+
- deleteHeader
|
|
39
|
+
- deleteFooter
|
|
40
|
+
- deletePositionedObject
|
|
41
|
+
- deleteNamedRange
|
|
42
|
+
- replaceImage
|
|
43
|
+
- replaceNamedRangeContent
|
|
44
|
+
- insertInlineImage
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
REPLACE_ALL_TEXT = "replaceAllText"
|
|
48
|
+
INSERT_TEXT = "insertText"
|
|
49
|
+
UPDATE_TEXT_STYLE = "updateTextStyle"
|
|
50
|
+
CREATE_PARAGRAPH_BULLETS = "createParagraphBullets"
|
|
51
|
+
DELETE_PARAGRAPH_BULLETS = "deleteParagraphBullets"
|
|
52
|
+
UPDATE_PARAGRAPH_STYLE = "updateParagraphStyle"
|
|
53
|
+
DELETE_CONTENT_RANGE = "deleteContentRange"
|
|
54
|
+
INSERT_TABLE = "insertTable"
|
|
55
|
+
INSERT_TABLE_ROW = "insertTableRow"
|
|
56
|
+
INSERT_TABLE_COLUMN = "insertTableColumn"
|
|
57
|
+
DELETE_TABLE_ROW = "deleteTableRow"
|
|
58
|
+
DELETE_TABLE_COLUMN = "deleteTableColumn"
|
|
59
|
+
UPDATE_TABLE_COLUMN_PROPERTIES = "updateTableColumnProperties"
|
|
60
|
+
UPDATE_TABLE_CELL_STYLE = "updateTableCellStyle"
|
|
61
|
+
UPDATE_TABLE_ROW_STYLE = "updateTableRowStyle"
|
|
62
|
+
PIN_TABLE_HEADER_ROWS = "pinTableHeaderRows"
|
|
63
|
+
UPDATE_DOCUMENT_STYLE = "updateDocumentStyle"
|
|
64
|
+
MERGE_TABLE_CELLS = "mergeTableCells"
|
|
65
|
+
UNMERGE_TABLE_CELLS = "unmergeTableCells"
|
|
66
|
+
UPDATE_SECTION_STYLE = "updateSectionStyle"
|
|
67
|
+
INSERT_SECTION_BREAK = "insertSectionBreak"
|
|
68
|
+
INSERT_PAGE_BREAK = "insertPageBreak"
|
|
69
|
+
|
|
70
|
+
def is_location_based(self) -> bool:
|
|
71
|
+
"""Whether the request type needs to specify indices for the location of the edit"""
|
|
72
|
+
location_based_requests_types = [
|
|
73
|
+
EditRequestType.INSERT_TEXT,
|
|
74
|
+
EditRequestType.INSERT_TABLE,
|
|
75
|
+
EditRequestType.INSERT_TABLE_ROW,
|
|
76
|
+
EditRequestType.INSERT_TABLE_COLUMN,
|
|
77
|
+
EditRequestType.DELETE_TABLE_ROW,
|
|
78
|
+
EditRequestType.DELETE_TABLE_COLUMN,
|
|
79
|
+
EditRequestType.UPDATE_TABLE_CELL_STYLE,
|
|
80
|
+
EditRequestType.MERGE_TABLE_CELLS,
|
|
81
|
+
EditRequestType.UNMERGE_TABLE_CELLS,
|
|
82
|
+
EditRequestType.INSERT_PAGE_BREAK,
|
|
83
|
+
EditRequestType.UPDATE_TABLE_ROW_STYLE,
|
|
84
|
+
EditRequestType.INSERT_SECTION_BREAK,
|
|
85
|
+
EditRequestType.PIN_TABLE_HEADER_ROWS,
|
|
86
|
+
EditRequestType.UPDATE_TEXT_STYLE,
|
|
87
|
+
EditRequestType.CREATE_PARAGRAPH_BULLETS,
|
|
88
|
+
EditRequestType.DELETE_PARAGRAPH_BULLETS,
|
|
89
|
+
EditRequestType.UPDATE_PARAGRAPH_STYLE,
|
|
90
|
+
EditRequestType.DELETE_CONTENT_RANGE,
|
|
91
|
+
EditRequestType.UPDATE_SECTION_STYLE,
|
|
92
|
+
]
|
|
93
|
+
return self in location_based_requests_types
|
|
94
|
+
|
|
95
|
+
def is_style_or_formatting_edit(self) -> bool:
|
|
96
|
+
"""Whether the request type is a style or formatting edit.
|
|
97
|
+
|
|
98
|
+
These types of edits can be safely batched together.
|
|
99
|
+
"""
|
|
100
|
+
style_formatting_edits = [
|
|
101
|
+
EditRequestType.UPDATE_TEXT_STYLE,
|
|
102
|
+
EditRequestType.UPDATE_PARAGRAPH_STYLE,
|
|
103
|
+
EditRequestType.UPDATE_TABLE_CELL_STYLE,
|
|
104
|
+
EditRequestType.UPDATE_TABLE_ROW_STYLE,
|
|
105
|
+
EditRequestType.UPDATE_TABLE_COLUMN_PROPERTIES,
|
|
106
|
+
EditRequestType.UPDATE_SECTION_STYLE,
|
|
107
|
+
EditRequestType.UPDATE_DOCUMENT_STYLE,
|
|
108
|
+
EditRequestType.PIN_TABLE_HEADER_ROWS,
|
|
109
|
+
EditRequestType.CREATE_PARAGRAPH_BULLETS,
|
|
110
|
+
EditRequestType.DELETE_PARAGRAPH_BULLETS,
|
|
111
|
+
]
|
|
112
|
+
return self in style_formatting_edits
|
|
113
|
+
|
|
114
|
+
def get_precedence(self) -> int:
|
|
115
|
+
"""
|
|
116
|
+
Returns the operation precedence for this edit request type.
|
|
117
|
+
|
|
118
|
+
Lower numbers indicate edits that should come earlier in the batch.
|
|
119
|
+
This is used for ordering edits to maintain document consistency.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
The precedence value (lower = earlier)
|
|
123
|
+
"""
|
|
124
|
+
precedence_mapping = {
|
|
125
|
+
# Document structure edits come first
|
|
126
|
+
EditRequestType.INSERT_SECTION_BREAK: 10,
|
|
127
|
+
EditRequestType.INSERT_PAGE_BREAK: 10,
|
|
128
|
+
# Table structure edits
|
|
129
|
+
EditRequestType.INSERT_TABLE: 20,
|
|
130
|
+
EditRequestType.INSERT_TABLE_ROW: 30,
|
|
131
|
+
EditRequestType.INSERT_TABLE_COLUMN: 30,
|
|
132
|
+
EditRequestType.DELETE_TABLE_ROW: 35,
|
|
133
|
+
EditRequestType.DELETE_TABLE_COLUMN: 35,
|
|
134
|
+
# List/bullet removal before creation
|
|
135
|
+
EditRequestType.DELETE_PARAGRAPH_BULLETS: 40,
|
|
136
|
+
# Content insertion edits
|
|
137
|
+
EditRequestType.REPLACE_ALL_TEXT: 45, # Replace before styling
|
|
138
|
+
EditRequestType.INSERT_TEXT: 50,
|
|
139
|
+
# List/bullet creation after removal
|
|
140
|
+
EditRequestType.CREATE_PARAGRAPH_BULLETS: 60,
|
|
141
|
+
# Merge edits
|
|
142
|
+
EditRequestType.MERGE_TABLE_CELLS: 70,
|
|
143
|
+
# Style and formatting edits come later
|
|
144
|
+
EditRequestType.UPDATE_TEXT_STYLE: 80,
|
|
145
|
+
EditRequestType.UPDATE_PARAGRAPH_STYLE: 80,
|
|
146
|
+
EditRequestType.UPDATE_TABLE_CELL_STYLE: 85,
|
|
147
|
+
EditRequestType.UPDATE_TABLE_ROW_STYLE: 85,
|
|
148
|
+
EditRequestType.UPDATE_TABLE_COLUMN_PROPERTIES: 85,
|
|
149
|
+
EditRequestType.UPDATE_SECTION_STYLE: 85,
|
|
150
|
+
EditRequestType.UPDATE_DOCUMENT_STYLE: 90,
|
|
151
|
+
EditRequestType.PIN_TABLE_HEADER_ROWS: 90,
|
|
152
|
+
# Unmerge operations
|
|
153
|
+
EditRequestType.UNMERGE_TABLE_CELLS: 95,
|
|
154
|
+
# Content removal edits come last
|
|
155
|
+
EditRequestType.DELETE_CONTENT_RANGE: 100,
|
|
156
|
+
}
|
|
157
|
+
return precedence_mapping.get(self, 75)
|
|
158
|
+
|
|
159
|
+
def get_request_model(self) -> type[BaseModel]:
|
|
160
|
+
"""
|
|
161
|
+
Returns the corresponding Pydantic model class for this edit request.
|
|
162
|
+
"""
|
|
163
|
+
mapping = {
|
|
164
|
+
EditRequestType.REPLACE_ALL_TEXT: ReplaceAllTextRequest,
|
|
165
|
+
EditRequestType.INSERT_TEXT: InsertTextRequest,
|
|
166
|
+
EditRequestType.UPDATE_TEXT_STYLE: UpdateTextStyleRequest,
|
|
167
|
+
EditRequestType.CREATE_PARAGRAPH_BULLETS: CreateParagraphBulletsRequest,
|
|
168
|
+
EditRequestType.DELETE_PARAGRAPH_BULLETS: DeleteParagraphBulletsRequest,
|
|
169
|
+
EditRequestType.UPDATE_PARAGRAPH_STYLE: UpdateParagraphStyleRequest,
|
|
170
|
+
EditRequestType.DELETE_CONTENT_RANGE: DeleteContentRangeRequest,
|
|
171
|
+
EditRequestType.INSERT_TABLE: InsertTableRequest,
|
|
172
|
+
EditRequestType.INSERT_TABLE_ROW: InsertTableRowRequest,
|
|
173
|
+
EditRequestType.INSERT_TABLE_COLUMN: InsertTableColumnRequest,
|
|
174
|
+
EditRequestType.DELETE_TABLE_ROW: DeleteTableRowRequest,
|
|
175
|
+
EditRequestType.DELETE_TABLE_COLUMN: DeleteTableColumnRequest,
|
|
176
|
+
EditRequestType.INSERT_PAGE_BREAK: InsertPageBreakRequest,
|
|
177
|
+
EditRequestType.UPDATE_TABLE_COLUMN_PROPERTIES: UpdateTableColumnPropertiesRequest,
|
|
178
|
+
EditRequestType.UPDATE_TABLE_CELL_STYLE: UpdateTableCellStyleRequest,
|
|
179
|
+
EditRequestType.UPDATE_TABLE_ROW_STYLE: UpdateTableRowStyleRequest,
|
|
180
|
+
EditRequestType.UPDATE_DOCUMENT_STYLE: UpdateDocumentStyleRequest,
|
|
181
|
+
EditRequestType.MERGE_TABLE_CELLS: MergeTableCellsRequest,
|
|
182
|
+
EditRequestType.UNMERGE_TABLE_CELLS: UnmergeTableCellsRequest,
|
|
183
|
+
EditRequestType.UPDATE_SECTION_STYLE: UpdateSectionStyleRequest,
|
|
184
|
+
EditRequestType.INSERT_SECTION_BREAK: InsertSectionBreakRequest,
|
|
185
|
+
EditRequestType.PIN_TABLE_HEADER_ROWS: PinTableHeaderRowsRequest,
|
|
186
|
+
}
|
|
187
|
+
return mapping[self] # type: ignore[return-value]
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class Request(BaseModel):
|
|
191
|
+
"""A request to edit a Google Document.
|
|
192
|
+
|
|
193
|
+
Does not include the following requests:
|
|
194
|
+
- createNamedRange
|
|
195
|
+
- deleteNamedRange
|
|
196
|
+
- insertInlineImage
|
|
197
|
+
- deletePositionedObject
|
|
198
|
+
- replaceImage
|
|
199
|
+
- createHeader
|
|
200
|
+
- createFooter
|
|
201
|
+
- createFootnote
|
|
202
|
+
- replaceNamedRangeContent
|
|
203
|
+
- deleteHeader
|
|
204
|
+
- deleteFooter
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
replaceAllText: ReplaceAllTextRequest | None = None
|
|
208
|
+
insertText: InsertTextRequest | None = None
|
|
209
|
+
updateTextStyle: UpdateTextStyleRequest | None = None
|
|
210
|
+
createParagraphBullets: CreateParagraphBulletsRequest | None = None
|
|
211
|
+
deleteParagraphBullets: DeleteParagraphBulletsRequest | None = None
|
|
212
|
+
updateParagraphStyle: UpdateParagraphStyleRequest | None = None
|
|
213
|
+
deleteContentRange: DeleteContentRangeRequest | None = None
|
|
214
|
+
insertTable: InsertTableRequest | None = None
|
|
215
|
+
insertTableRow: InsertTableRowRequest | None = None
|
|
216
|
+
insertTableColumn: InsertTableColumnRequest | None = None
|
|
217
|
+
deleteTableRow: DeleteTableRowRequest | None = None
|
|
218
|
+
deleteTableColumn: DeleteTableColumnRequest | None = None
|
|
219
|
+
insertPageBreak: InsertPageBreakRequest | None = None
|
|
220
|
+
updateTableColumnProperties: UpdateTableColumnPropertiesRequest | None = None
|
|
221
|
+
updateTableCellStyle: UpdateTableCellStyleRequest | None = None
|
|
222
|
+
updateTableRowStyle: UpdateTableRowStyleRequest | None = None
|
|
223
|
+
updateDocumentStyle: UpdateDocumentStyleRequest | None = None
|
|
224
|
+
mergeTableCells: MergeTableCellsRequest | None = None
|
|
225
|
+
unmergeTableCells: UnmergeTableCellsRequest | None = None
|
|
226
|
+
updateSectionStyle: UpdateSectionStyleRequest | None = None
|
|
227
|
+
insertSectionBreak: InsertSectionBreakRequest | None = None
|
|
228
|
+
pinTableHeaderRows: PinTableHeaderRowsRequest | None = None
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class ReplaceAllTextRequest(BaseModel):
|
|
232
|
+
model_config = ConfigDict(
|
|
233
|
+
title="Replaces all instances of text matching a criteria with replace text"
|
|
234
|
+
)
|
|
235
|
+
replaceText: str = Field(..., title="The text that will replace the matched text.")
|
|
236
|
+
tabsCriteria: TabsCriteria | None = Field(
|
|
237
|
+
None,
|
|
238
|
+
title=(
|
|
239
|
+
"Optional. The criteria used to specify in which tabs the replacement occurs. "
|
|
240
|
+
"When omitted, the replacement applies to all tabs."
|
|
241
|
+
),
|
|
242
|
+
)
|
|
243
|
+
containsText: SubstringMatchCriteria = Field(
|
|
244
|
+
..., title="Finds text in the document matching this substring."
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class TabsCriteria(BaseModel):
|
|
249
|
+
model_config = ConfigDict(title="A criteria that specifies in which tabs a request executes.")
|
|
250
|
+
tabIds: list[str] = Field(
|
|
251
|
+
..., title="The list of tab IDs in which the request executes.", min_length=1
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class SubstringMatchCriteria(BaseModel):
|
|
256
|
+
model_config = ConfigDict(
|
|
257
|
+
title="A criteria that matches a specific string of text in the document."
|
|
258
|
+
)
|
|
259
|
+
text: str = Field(..., title="The text to search for in the document.")
|
|
260
|
+
matchCase: bool = Field(
|
|
261
|
+
...,
|
|
262
|
+
title=(
|
|
263
|
+
"Indicates whether the search should respect case. "
|
|
264
|
+
"True: the search is case sensitive. False: the search is case insensitive."
|
|
265
|
+
),
|
|
266
|
+
)
|
|
267
|
+
searchByRegex: bool | None = Field(
|
|
268
|
+
None,
|
|
269
|
+
title=(
|
|
270
|
+
"Optional. True if the find value should be treated as a regular expression. "
|
|
271
|
+
"Any backslashes in the pattern should be escaped. "
|
|
272
|
+
"True: the search text is treated as a regular expression. "
|
|
273
|
+
"False: the search text is treated as a substring for matching."
|
|
274
|
+
),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class InsertTextRequest(BaseModel):
|
|
279
|
+
model_config = ConfigDict(title="Inserts text at the specified location.")
|
|
280
|
+
text: str = Field(
|
|
281
|
+
...,
|
|
282
|
+
title=(
|
|
283
|
+
"The text to be inserted. Inserting a newline character will implicitly create a new "
|
|
284
|
+
"Paragraph at that index. The paragraph style of the new paragraph will be copied from "
|
|
285
|
+
"the paragraph at the current insertion index, including lists and bullets. Text "
|
|
286
|
+
"styles for inserted text will be determined automatically, generally preserving the "
|
|
287
|
+
"styling "
|
|
288
|
+
"of neighboring text. In most cases, the text style for the inserted text will match "
|
|
289
|
+
"the text immediately before the insertion index. If your insertion is technically "
|
|
290
|
+
"an 'append' to the end of a section, then this index should be equal to the "
|
|
291
|
+
"'end index' of the section's range"
|
|
292
|
+
),
|
|
293
|
+
)
|
|
294
|
+
insertion_location: Location | EndOfSegmentLocation = Field(
|
|
295
|
+
...,
|
|
296
|
+
title=(
|
|
297
|
+
"Union field insertion_location. The location where the text will be inserted. "
|
|
298
|
+
"insertion_location can be only one of the following: "
|
|
299
|
+
"location — Text must be inserted inside the bounds of an existing Paragraph. "
|
|
300
|
+
"For instance, text cannot be inserted at a table's start index "
|
|
301
|
+
"(i.e. between the table and its preceding paragraph). "
|
|
302
|
+
"The text must be inserted in the preceding paragraph. "
|
|
303
|
+
"endOfSegmentLocation — Inserts the text at the end of a header, footer, footnote or "
|
|
304
|
+
"the document body. Prefer this option when you want to 'append' text to the end of a "
|
|
305
|
+
"section."
|
|
306
|
+
),
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
@model_serializer(mode="wrap")
|
|
310
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
311
|
+
"""
|
|
312
|
+
Modify/wraps the result of the handler to resolve the union field insertion_location
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
handler: The handler function that would normally return the model's data
|
|
316
|
+
such as `model_dump` or `model_json_schema`.
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
The modified data with the union field resolved.
|
|
320
|
+
"""
|
|
321
|
+
data = handler(self)
|
|
322
|
+
data.pop("insertion_location", None)
|
|
323
|
+
if isinstance(self.insertion_location, Location):
|
|
324
|
+
data["location"] = self.insertion_location.model_dump(exclude_none=True)
|
|
325
|
+
elif isinstance(self.insertion_location, EndOfSegmentLocation):
|
|
326
|
+
data["endOfSegmentLocation"] = self.insertion_location.model_dump(exclude_none=True)
|
|
327
|
+
return data
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class Location(BaseModel):
|
|
331
|
+
model_config = ConfigDict(title="A particular location in the document.")
|
|
332
|
+
segmentId: str | None = Field(
|
|
333
|
+
None,
|
|
334
|
+
title="An empty segment ID signifies the document's body.",
|
|
335
|
+
)
|
|
336
|
+
index: int = Field(
|
|
337
|
+
...,
|
|
338
|
+
title=(
|
|
339
|
+
"The zero-based index. The index is relative to the beginning of the segment specified "
|
|
340
|
+
"by segmentId. If your insertion is technically an 'append' to the end of a section, "
|
|
341
|
+
"then this index should be equal to the 'end index' of the section's range"
|
|
342
|
+
),
|
|
343
|
+
ge=0,
|
|
344
|
+
)
|
|
345
|
+
tabId: str | None = Field(
|
|
346
|
+
None,
|
|
347
|
+
title=(
|
|
348
|
+
"The tab that the location is in. "
|
|
349
|
+
"When omitted, the request is applied to the first tab."
|
|
350
|
+
),
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class EndOfSegmentLocation(BaseModel):
|
|
355
|
+
model_config = ConfigDict(
|
|
356
|
+
title=(
|
|
357
|
+
"Location at the end of a body, header, footer or footnote. "
|
|
358
|
+
"The location is immediately before the last newline in the document segment."
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
segmentId: str | None = Field(
|
|
362
|
+
None,
|
|
363
|
+
title=(
|
|
364
|
+
"The ID of the header, footer or footnote the location is in. "
|
|
365
|
+
"An empty segment ID signifies the document's body."
|
|
366
|
+
),
|
|
367
|
+
)
|
|
368
|
+
tabId: str | None = Field(
|
|
369
|
+
None,
|
|
370
|
+
title=(
|
|
371
|
+
"The tab that the location is in. "
|
|
372
|
+
"When omitted, the request is applied to the first tab."
|
|
373
|
+
),
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
class UpdateTextStyleFields(str, Enum):
|
|
378
|
+
BOLD = "bold"
|
|
379
|
+
ITALIC = "italic"
|
|
380
|
+
UNDERLINE = "underline"
|
|
381
|
+
STRIKETHROUGH = "strikethrough"
|
|
382
|
+
SMALL_CAPS = "smallCaps"
|
|
383
|
+
BACKGROUND_COLOR = "backgroundColor"
|
|
384
|
+
FOREGROUND_COLOR = "foregroundColor"
|
|
385
|
+
FONT_SIZE = "fontSize"
|
|
386
|
+
FONT_FAMILY = "fontFamily"
|
|
387
|
+
WEIGHT = "weight"
|
|
388
|
+
BASELINE_OFFSET = "baselineOffset"
|
|
389
|
+
LINK = "link"
|
|
390
|
+
ALL = "*"
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
class UpdateTextStyleRequest(BaseModel):
|
|
394
|
+
model_config = ConfigDict(title="Update the styling of text.")
|
|
395
|
+
textStyle: TextStyleWritable = Field(
|
|
396
|
+
...,
|
|
397
|
+
title=(
|
|
398
|
+
"The styles to set on the text. If the value for a particular style matches that "
|
|
399
|
+
"of the parent, that style will be set to inherit. Certain text style changes may "
|
|
400
|
+
"cause other changes in order to mirror the behavior of the Docs editor. See the "
|
|
401
|
+
"documentation of TextStyle for more information."
|
|
402
|
+
),
|
|
403
|
+
)
|
|
404
|
+
fields: list[UpdateTextStyleFields] = Field(
|
|
405
|
+
...,
|
|
406
|
+
title=(
|
|
407
|
+
"The fields that should be updated. At least one field must be specified. The root "
|
|
408
|
+
"textStyle is implied and should not be specified. A single '*' can be used as "
|
|
409
|
+
"short-hand for listing every field. For example, to update the text style to bold, "
|
|
410
|
+
"set fields to 'bold'. To reset a property to its default value, include its field "
|
|
411
|
+
"name in the field mask but leave the field itself unset."
|
|
412
|
+
),
|
|
413
|
+
)
|
|
414
|
+
range: RangeWritable = Field(
|
|
415
|
+
...,
|
|
416
|
+
title=(
|
|
417
|
+
"The range of text to style. The range may be extended to include adjacent newlines. "
|
|
418
|
+
"If the range fully contains a paragraph belonging to a list, the paragraph's bullet "
|
|
419
|
+
"is also updated with the matching text style. Ranges cannot be inserted inside a "
|
|
420
|
+
"relative UpdateTextStyleRequest."
|
|
421
|
+
),
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
@model_serializer(mode="wrap")
|
|
425
|
+
def _resolve_fields(self, handler: Callable[[Any], Any]) -> Any:
|
|
426
|
+
"""
|
|
427
|
+
Modify/wraps the result of the handler to resolve the union field 'fields'
|
|
428
|
+
to a comma-separated string.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
handler: The handler function that would normally return the model's data
|
|
432
|
+
such as `model_dump` or `model_json_schema`.
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
The modified data with the union field resolved.
|
|
436
|
+
"""
|
|
437
|
+
data = handler(self)
|
|
438
|
+
data.pop("fields", None)
|
|
439
|
+
if all(isinstance(field, UpdateTextStyleFields) for field in self.fields):
|
|
440
|
+
if UpdateTextStyleFields.ALL in self.fields:
|
|
441
|
+
data["fields"] = "*"
|
|
442
|
+
else:
|
|
443
|
+
data["fields"] = ",".join([field.value for field in self.fields])
|
|
444
|
+
return data
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
class CreateParagraphBulletsRequest(BaseModel):
|
|
448
|
+
model_config = ConfigDict(
|
|
449
|
+
title=(
|
|
450
|
+
"Creates bullets for all of the paragraphs that overlap with the given range. The "
|
|
451
|
+
"nesting level is determined by leading tabs, which are removed to avoid excess space."
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
range: RangeWritable = Field(
|
|
455
|
+
...,
|
|
456
|
+
title="The range to apply the bullet preset to.",
|
|
457
|
+
)
|
|
458
|
+
bulletPreset: BulletGlyphPreset = Field(
|
|
459
|
+
...,
|
|
460
|
+
title="The kinds of bullet glyphs to be used.",
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
class BulletGlyphPreset(str, Enum):
|
|
465
|
+
BULLET_GLYPH_PRESET_UNSPECIFIED = "BULLET_GLYPH_PRESET_UNSPECIFIED"
|
|
466
|
+
BULLET_DISC_CIRCLE_SQUARE = "BULLET_DISC_CIRCLE_SQUARE"
|
|
467
|
+
BULLET_DIAMONDX_ARROW3D_SQUARE = "BULLET_DIAMONDX_ARROW3D_SQUARE"
|
|
468
|
+
BULLET_CHECKBOX = "BULLET_CHECKBOX"
|
|
469
|
+
BULLET_ARROW_DIAMOND_DISC = "BULLET_ARROW_DIAMOND_DISC"
|
|
470
|
+
BULLET_STAR_CIRCLE_SQUARE = "BULLET_STAR_CIRCLE_SQUARE"
|
|
471
|
+
BULLET_ARROW3D_CIRCLE_SQUARE = "BULLET_ARROW3D_CIRCLE_SQUARE"
|
|
472
|
+
BULLET_LEFTTRIANGLE_DIAMOND_DISC = "BULLET_LEFTTRIANGLE_DIAMOND_DISC"
|
|
473
|
+
BULLET_DIAMONDX_HOLLOWDIAMOND_SQUARE = "BULLET_DIAMONDX_HOLLOWDIAMOND_SQUARE"
|
|
474
|
+
BULLET_DIAMOND_CIRCLE_SQUARE = "BULLET_DIAMOND_CIRCLE_SQUARE"
|
|
475
|
+
NUMBERED_DECIMAL_ALPHA_ROMAN = "NUMBERED_DECIMAL_ALPHA_ROMAN"
|
|
476
|
+
NUMBERED_DECIMAL_ALPHA_ROMAN_PARENS = "NUMBERED_DECIMAL_ALPHA_ROMAN_PARENS"
|
|
477
|
+
NUMBERED_DECIMAL_NESTED = "NUMBERED_DECIMAL_NESTED"
|
|
478
|
+
NUMBERED_UPPERALPHA_ALPHA_ROMAN = "NUMBERED_UPPERALPHA_ALPHA_ROMAN"
|
|
479
|
+
NUMBERED_UPPERROMAN_UPPERALPHA_DECIMAL = "NUMBERED_UPPERROMAN_UPPERALPHA_DECIMAL"
|
|
480
|
+
NUMBERED_ZERODECIMAL_ALPHA_ROMAN = "NUMBERED_ZERODECIMAL_ALPHA_ROMAN"
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
class DeleteParagraphBulletsRequest(BaseModel):
|
|
484
|
+
model_config = ConfigDict(
|
|
485
|
+
title=(
|
|
486
|
+
"Deletes bullets from all of the paragraphs that overlap with the given range. "
|
|
487
|
+
"The nesting level is visually preserved by adding indent to the start of the "
|
|
488
|
+
"paragraph."
|
|
489
|
+
)
|
|
490
|
+
)
|
|
491
|
+
range: RangeWritable = Field(
|
|
492
|
+
...,
|
|
493
|
+
title="The range to delete bullets from.",
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
class CreateNamedRangeRequest(BaseModel):
|
|
498
|
+
model_config = ConfigDict(title="Creates a NamedRange referencing the given range.")
|
|
499
|
+
name: str = Field(
|
|
500
|
+
...,
|
|
501
|
+
min_length=1,
|
|
502
|
+
max_length=256,
|
|
503
|
+
title=(
|
|
504
|
+
"The name of the NamedRange. Names do not need to be unique. Names must be at least "
|
|
505
|
+
"1 character and no more than 256 characters (UTF-16 code units)."
|
|
506
|
+
),
|
|
507
|
+
)
|
|
508
|
+
range: RangeWritable = Field(
|
|
509
|
+
...,
|
|
510
|
+
title="The range to apply the name to.",
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
class DeleteNamedRangeRequest(BaseModel):
|
|
515
|
+
class NameRangeId(BaseModel):
|
|
516
|
+
model_config = ConfigDict(title="The ID of the named range to delete.")
|
|
517
|
+
namedRangeId: str = Field(
|
|
518
|
+
...,
|
|
519
|
+
title="The ID of the named range to delete.",
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
class Name(BaseModel):
|
|
523
|
+
model_config = ConfigDict(title="The name of the range(s) to delete.")
|
|
524
|
+
name: str = Field(
|
|
525
|
+
...,
|
|
526
|
+
title="The name of the range(s) to delete.",
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
model_config = ConfigDict(title="Deletes a NamedRange.")
|
|
530
|
+
tabsCriteria: TabsCriteria | None = Field(
|
|
531
|
+
None,
|
|
532
|
+
title=(
|
|
533
|
+
"Optional. The criteria used to specify which tab(s) "
|
|
534
|
+
"the range deletion should occur in. "
|
|
535
|
+
"When omitted, the range deletion is applied to all tabs."
|
|
536
|
+
),
|
|
537
|
+
)
|
|
538
|
+
named_range_reference: NameRangeId | Name = Field(
|
|
539
|
+
...,
|
|
540
|
+
title=(
|
|
541
|
+
"Union field named_range_reference. "
|
|
542
|
+
"The value that determines which range or ranges to delete. Exactly one must be set. "
|
|
543
|
+
"named_range_reference can be only one of the following:\n"
|
|
544
|
+
"namedRangeId - The ID of the named range to delete.\n"
|
|
545
|
+
"name - The name of the range(s) to delete. All named ranges with the given name will be deleted." # noqa: E501
|
|
546
|
+
),
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
@model_serializer(mode="wrap")
|
|
550
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
551
|
+
"""
|
|
552
|
+
Modify/wraps the result of the handler to resolve the union field named_range_reference
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
handler: The handler function that would normally return the model's data
|
|
556
|
+
such as `model_dump` or `model_json_schema`.
|
|
557
|
+
|
|
558
|
+
Returns:
|
|
559
|
+
The modified data with the union field resolved.
|
|
560
|
+
"""
|
|
561
|
+
data = handler(self)
|
|
562
|
+
data.pop("named_range_reference", None)
|
|
563
|
+
# Add the API-expected field based on the concrete type
|
|
564
|
+
if isinstance(self.named_range_reference, ReplaceNamedRangeContentRequest.NamedRangeIdRef):
|
|
565
|
+
data["namedRangeId"] = self.named_range_reference.namedRangeId
|
|
566
|
+
elif isinstance(
|
|
567
|
+
self.named_range_reference, ReplaceNamedRangeContentRequest.NamedRangeNameRef
|
|
568
|
+
):
|
|
569
|
+
data["name"] = self.named_range_reference.namedRangeName
|
|
570
|
+
return data
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
class UpdateParagraphStyleRequest(BaseModel):
|
|
574
|
+
model_config = ConfigDict(
|
|
575
|
+
title="Update the styling of all paragraphs that overlap with the given range."
|
|
576
|
+
)
|
|
577
|
+
paragraphStyle: ParagraphStyleWritable = Field(
|
|
578
|
+
...,
|
|
579
|
+
title=(
|
|
580
|
+
"The styles to set on the paragraphs. Certain paragraph style changes may cause other "
|
|
581
|
+
"changes in order to mirror the behavior of the Docs editor. See the documentation of "
|
|
582
|
+
"ParagraphStyle for more information."
|
|
583
|
+
),
|
|
584
|
+
)
|
|
585
|
+
# TODO: Create a UpdateParagraphStyleFields enum to reduce LLM hallucinations.
|
|
586
|
+
# See UpdateTextStyleRequest for an example.
|
|
587
|
+
fields: str = Field(
|
|
588
|
+
...,
|
|
589
|
+
title=(
|
|
590
|
+
"The fields that should be updated. At least one field must be specified. The root "
|
|
591
|
+
"paragraphStyle is implied and should not be specified. A single '*' can be used as "
|
|
592
|
+
"short-hand for listing every field. For example, to update the paragraph style's "
|
|
593
|
+
"alignment property, set fields to 'alignment'. To reset a property to its default "
|
|
594
|
+
"value, include its field name in the field mask but leave the field itself unset."
|
|
595
|
+
),
|
|
596
|
+
)
|
|
597
|
+
range: RangeWritable = Field(
|
|
598
|
+
...,
|
|
599
|
+
title=("The range overlapping the paragraphs to style."),
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
class DeleteContentRangeRequest(BaseModel):
|
|
604
|
+
model_config = ConfigDict(title="Deletes content from the document.")
|
|
605
|
+
range: RangeWritable = Field(
|
|
606
|
+
...,
|
|
607
|
+
title=(
|
|
608
|
+
"The range of content to delete. Deleting text that crosses a paragraph boundary may "
|
|
609
|
+
"result in changes to paragraph styles, lists, positioned objects and bookmarks as the "
|
|
610
|
+
"two paragraphs are merged. Attempting to delete certain ranges can result in an "
|
|
611
|
+
"invalid document structure."
|
|
612
|
+
),
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
class InsertInlineImageRequest(BaseModel):
|
|
617
|
+
model_config = ConfigDict(
|
|
618
|
+
title="Inserts an InlineObject containing an image at the given location."
|
|
619
|
+
)
|
|
620
|
+
uri: str = Field(
|
|
621
|
+
...,
|
|
622
|
+
title=(
|
|
623
|
+
"The image URI. The image is fetched once at insertion time and a copy is stored for "
|
|
624
|
+
"display inside the document. Must be publicly accessible and <= 2 kB."
|
|
625
|
+
),
|
|
626
|
+
)
|
|
627
|
+
objectSize: SizeWritable | None = Field(
|
|
628
|
+
None,
|
|
629
|
+
title=(
|
|
630
|
+
"The size the image should appear as in the document. If neither width nor height is "
|
|
631
|
+
"specified, a default size is calculated. If one dimension is specified, the other is "
|
|
632
|
+
"calculated to preserve aspect ratio. If both are specified, the image is scaled to "
|
|
633
|
+
"fit within provided dimensions while maintaining aspect ratio."
|
|
634
|
+
),
|
|
635
|
+
)
|
|
636
|
+
insertion_location: Location | EndOfSegmentLocation = Field(
|
|
637
|
+
...,
|
|
638
|
+
title=(
|
|
639
|
+
"Union field insertion_location. The location where the image will be inserted. "
|
|
640
|
+
"location — Inserts at a specific index inside an existing Paragraph. "
|
|
641
|
+
"endOfSegmentLocation — Inserts at the end of a header, footer or the body."
|
|
642
|
+
),
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
@model_serializer(mode="wrap")
|
|
646
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
647
|
+
"""
|
|
648
|
+
Modify/wraps the result of the handler to resolve the union field insertion_location
|
|
649
|
+
|
|
650
|
+
Args:
|
|
651
|
+
handler: The handler function that would normally return the model's data
|
|
652
|
+
such as `model_dump` or `model_json_schema`.
|
|
653
|
+
|
|
654
|
+
Returns:
|
|
655
|
+
The modified data with the union field resolved.
|
|
656
|
+
"""
|
|
657
|
+
data = handler(self)
|
|
658
|
+
data.pop("insertion_location", None)
|
|
659
|
+
if isinstance(self.insertion_location, Location):
|
|
660
|
+
data["location"] = self.insertion_location.model_dump(exclude_none=True)
|
|
661
|
+
elif isinstance(self.insertion_location, EndOfSegmentLocation):
|
|
662
|
+
data["endOfSegmentLocation"] = self.insertion_location.model_dump(exclude_none=True)
|
|
663
|
+
return data
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
class InsertTableRequest(BaseModel):
|
|
667
|
+
model_config = ConfigDict(title="Inserts a table at the specified location.")
|
|
668
|
+
rows: int = Field(
|
|
669
|
+
...,
|
|
670
|
+
ge=1,
|
|
671
|
+
title="The number of rows in the table.",
|
|
672
|
+
)
|
|
673
|
+
columns: int = Field(
|
|
674
|
+
...,
|
|
675
|
+
ge=1,
|
|
676
|
+
title="The number of columns in the table.",
|
|
677
|
+
)
|
|
678
|
+
insertion_location: Location | EndOfSegmentLocation = Field(
|
|
679
|
+
...,
|
|
680
|
+
title=(
|
|
681
|
+
"Union field insertion_location. The location where the table will be inserted. "
|
|
682
|
+
"location — Inserts at a specific model index (table start index will be location+1). "
|
|
683
|
+
"endOfSegmentLocation — Inserts at the end of the given header, footer or body."
|
|
684
|
+
),
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
@model_serializer(mode="wrap")
|
|
688
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
689
|
+
"""
|
|
690
|
+
Modify/wraps the result of the handler to resolve the union field insertion_location
|
|
691
|
+
|
|
692
|
+
Args:
|
|
693
|
+
handler: The handler function that would normally return the model's data
|
|
694
|
+
such as `model_dump` or `model_json_schema`.
|
|
695
|
+
|
|
696
|
+
Returns:
|
|
697
|
+
The modified data with the union field resolved.
|
|
698
|
+
"""
|
|
699
|
+
data = handler(self)
|
|
700
|
+
data.pop("insertion_location", None)
|
|
701
|
+
if isinstance(self.insertion_location, Location):
|
|
702
|
+
data["location"] = self.insertion_location.model_dump(exclude_none=True)
|
|
703
|
+
elif isinstance(self.insertion_location, EndOfSegmentLocation):
|
|
704
|
+
data["endOfSegmentLocation"] = self.insertion_location.model_dump(exclude_none=True)
|
|
705
|
+
return data
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
class InsertTableRowRequest(BaseModel):
|
|
709
|
+
model_config = ConfigDict(title="Inserts an empty row into a table.")
|
|
710
|
+
tableCellLocation: TableCellLocation = Field(
|
|
711
|
+
...,
|
|
712
|
+
title=("The reference table cell location from which rows will be inserted."),
|
|
713
|
+
)
|
|
714
|
+
insertBelow: bool = Field(
|
|
715
|
+
...,
|
|
716
|
+
title=(
|
|
717
|
+
"Whether to insert the new row below the reference cell location. "
|
|
718
|
+
"True: below, False: above."
|
|
719
|
+
),
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
class TableCellLocation(BaseModel):
|
|
724
|
+
model_config = ConfigDict(title="Location of a single cell within a table.")
|
|
725
|
+
tableStartLocation: Location = Field(
|
|
726
|
+
...,
|
|
727
|
+
title="The location where the table starts in the document.",
|
|
728
|
+
)
|
|
729
|
+
rowIndex: int = Field(
|
|
730
|
+
...,
|
|
731
|
+
ge=0,
|
|
732
|
+
title=("The zero-based row index. For example, the second row has a row index of 1."),
|
|
733
|
+
)
|
|
734
|
+
columnIndex: int = Field(
|
|
735
|
+
...,
|
|
736
|
+
ge=0,
|
|
737
|
+
title=(
|
|
738
|
+
"The zero-based column index. For example, the second column has a column index of 1."
|
|
739
|
+
),
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
class InsertTableColumnRequest(BaseModel):
|
|
744
|
+
model_config = ConfigDict(title="Inserts an empty column into a table.")
|
|
745
|
+
tableCellLocation: TableCellLocation = Field(
|
|
746
|
+
...,
|
|
747
|
+
title=("The reference table cell location from which columns will be inserted."),
|
|
748
|
+
)
|
|
749
|
+
insertRight: bool = Field(
|
|
750
|
+
...,
|
|
751
|
+
title=(
|
|
752
|
+
"Whether to insert the new column to the right of the reference cell location. "
|
|
753
|
+
"True: right, False: left."
|
|
754
|
+
),
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
class DeleteTableRowRequest(BaseModel):
|
|
759
|
+
model_config = ConfigDict(title="Deletes a row from a table.")
|
|
760
|
+
tableCellLocation: TableCellLocation = Field(
|
|
761
|
+
...,
|
|
762
|
+
title=("The reference table cell location from which the row will be deleted."),
|
|
763
|
+
)
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
class DeleteTableColumnRequest(BaseModel):
|
|
767
|
+
model_config = ConfigDict(title="Deletes a column from a table.")
|
|
768
|
+
tableCellLocation: TableCellLocation = Field(
|
|
769
|
+
...,
|
|
770
|
+
title=("The reference table cell location from which the column will be deleted."),
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
class InsertPageBreakRequest(BaseModel):
|
|
775
|
+
model_config = ConfigDict(
|
|
776
|
+
title="Inserts a page break followed by a newline at the specified location."
|
|
777
|
+
)
|
|
778
|
+
insertion_location: Location | EndOfSegmentLocation = Field(
|
|
779
|
+
...,
|
|
780
|
+
title=(
|
|
781
|
+
"Union field insertion_location. The location where the page break will be inserted. "
|
|
782
|
+
"location — Inserts at a specific index inside an existing Paragraph; cannot be inside "
|
|
783
|
+
"a table, equation, footnote, header or footer. Segment ID must be empty (body only). "
|
|
784
|
+
"endOfSegmentLocation — Inserts at the end of the document body; cannot be inside a "
|
|
785
|
+
"footnote, header or footer. Segment ID must be empty (body only)."
|
|
786
|
+
),
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
@model_serializer(mode="wrap")
|
|
790
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
791
|
+
"""
|
|
792
|
+
Modify/wraps the result of the handler to resolve the union field insertion_location
|
|
793
|
+
|
|
794
|
+
Args:
|
|
795
|
+
handler: The handler function that would normally return the model's data
|
|
796
|
+
such as `model_dump` or `model_json_schema`.
|
|
797
|
+
|
|
798
|
+
Returns:
|
|
799
|
+
The modified data with the union field resolved.
|
|
800
|
+
"""
|
|
801
|
+
data = handler(self)
|
|
802
|
+
data.pop("insertion_location", None)
|
|
803
|
+
if isinstance(self.insertion_location, Location):
|
|
804
|
+
data["location"] = self.insertion_location.model_dump(exclude_none=True)
|
|
805
|
+
elif isinstance(self.insertion_location, EndOfSegmentLocation):
|
|
806
|
+
data["endOfSegmentLocation"] = self.insertion_location.model_dump(exclude_none=True)
|
|
807
|
+
return data
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
class DeletePositionedObjectRequest(BaseModel):
|
|
811
|
+
model_config = ConfigDict(title="Deletes a PositionedObject from the document.")
|
|
812
|
+
objectId: str = Field(
|
|
813
|
+
...,
|
|
814
|
+
title="The ID of the positioned object to delete.",
|
|
815
|
+
)
|
|
816
|
+
tabId: str | None = Field(
|
|
817
|
+
None,
|
|
818
|
+
title=(
|
|
819
|
+
"The tab that the positioned object to delete is in. When omitted, the request is "
|
|
820
|
+
"applied to the first tab."
|
|
821
|
+
),
|
|
822
|
+
)
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
class UpdateTableColumnPropertiesRequest(BaseModel):
|
|
826
|
+
model_config = ConfigDict(title="Updates the TableColumnProperties of columns in a table.")
|
|
827
|
+
tableStartLocation: Location = Field(
|
|
828
|
+
...,
|
|
829
|
+
title="The location where the table starts in the document.",
|
|
830
|
+
)
|
|
831
|
+
columnIndices: list[int] | None = Field(
|
|
832
|
+
None,
|
|
833
|
+
title=(
|
|
834
|
+
"The list of zero-based column indices whose property should be updated. If no indices "
|
|
835
|
+
"are specified, all columns will be updated."
|
|
836
|
+
),
|
|
837
|
+
)
|
|
838
|
+
tableColumnProperties: TableColumnPropertiesWritable = Field(
|
|
839
|
+
...,
|
|
840
|
+
title=(
|
|
841
|
+
"The table column properties to update. If width is less than 5 points, a 400 error "
|
|
842
|
+
"is returned."
|
|
843
|
+
),
|
|
844
|
+
)
|
|
845
|
+
# TODO: Create a UpdateTableColumnPropertiesFields enum to reduce LLM hallucinations.
|
|
846
|
+
# See UpdateTextStyleRequest for an example.
|
|
847
|
+
fields: str = Field(
|
|
848
|
+
...,
|
|
849
|
+
title=(
|
|
850
|
+
"The fields that should be updated. At least one field must be specified. Allowed: "
|
|
851
|
+
'"width", "widthType", or "*". Use comma-separated list for multiple, e.g., '
|
|
852
|
+
'"width,widthType".'
|
|
853
|
+
),
|
|
854
|
+
)
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
class UpdateTableCellStyleRequest(BaseModel):
|
|
858
|
+
model_config = ConfigDict(title="Updates the style of a range of table cells.")
|
|
859
|
+
tableCellStyle: TableCellStyleWritable = Field(
|
|
860
|
+
...,
|
|
861
|
+
title=(
|
|
862
|
+
"The style to set on the table cells. When updating borders, adjacent shared borders "
|
|
863
|
+
"are updated as well; merged and invisible borders are not updated."
|
|
864
|
+
),
|
|
865
|
+
)
|
|
866
|
+
# TODO: Create a UpdateTableCellStyleFields enum to reduce LLM hallucinations.
|
|
867
|
+
# See UpdateTextStyleRequest for an example.
|
|
868
|
+
fields: str = Field(
|
|
869
|
+
...,
|
|
870
|
+
title=(
|
|
871
|
+
"The fields that should be updated. At least one field must be specified. The root "
|
|
872
|
+
"tableCellStyle is implied and should not be specified. A single '*' can be used as "
|
|
873
|
+
"short-hand for listing every field. For example to update the table cell background "
|
|
874
|
+
"color, set fields to 'backgroundColor'. To reset a property to its default value, "
|
|
875
|
+
"include its field name in the field mask but leave the field itself unset."
|
|
876
|
+
),
|
|
877
|
+
)
|
|
878
|
+
cells: TableRange | Location = Field(
|
|
879
|
+
...,
|
|
880
|
+
title=(
|
|
881
|
+
"Union field cells. The cells which will be updated. "
|
|
882
|
+
"tableRange — The subset of the table to which the updates are applied. "
|
|
883
|
+
"tableStartLocation — The location where the table starts; applies updates to all "
|
|
884
|
+
"cells in the table."
|
|
885
|
+
),
|
|
886
|
+
)
|
|
887
|
+
|
|
888
|
+
@model_serializer(mode="wrap")
|
|
889
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
890
|
+
"""
|
|
891
|
+
Modify/wraps the result of the handler to resolve the union field cells
|
|
892
|
+
|
|
893
|
+
Args:
|
|
894
|
+
handler: The handler function that would normally return the model's data
|
|
895
|
+
such as `model_dump` or `model_json_schema`.
|
|
896
|
+
|
|
897
|
+
Returns:
|
|
898
|
+
The modified data with the union field resolved.
|
|
899
|
+
"""
|
|
900
|
+
data = handler(self)
|
|
901
|
+
data.pop("cells", None)
|
|
902
|
+
if isinstance(self.cells, TableRange):
|
|
903
|
+
data["tableRange"] = self.cells.model_dump(exclude_none=True)
|
|
904
|
+
elif isinstance(self.cells, Location):
|
|
905
|
+
data["tableStartLocation"] = self.cells.model_dump(exclude_none=True)
|
|
906
|
+
return data
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
class TableRange(BaseModel):
|
|
910
|
+
model_config = ConfigDict(title="A table range represents a reference to a subset of a table.")
|
|
911
|
+
tableCellLocation: TableCellLocation = Field(
|
|
912
|
+
...,
|
|
913
|
+
title="The cell location where the table range starts.",
|
|
914
|
+
)
|
|
915
|
+
rowSpan: int = Field(
|
|
916
|
+
...,
|
|
917
|
+
title="The row span of the table range.",
|
|
918
|
+
)
|
|
919
|
+
columnSpan: int = Field(
|
|
920
|
+
...,
|
|
921
|
+
title="The column span of the table range.",
|
|
922
|
+
)
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
class UpdateTableRowStyleRequest(BaseModel):
|
|
926
|
+
model_config = ConfigDict(title="Updates the TableRowStyle of rows in a table.")
|
|
927
|
+
tableStartLocation: Location = Field(
|
|
928
|
+
...,
|
|
929
|
+
title="The location where the table starts in the document.",
|
|
930
|
+
)
|
|
931
|
+
rowIndices: list[int] | None = Field(
|
|
932
|
+
None,
|
|
933
|
+
title=(
|
|
934
|
+
"The list of zero-based row indices whose style should be updated. If no indices "
|
|
935
|
+
"are specified, all rows will be updated."
|
|
936
|
+
),
|
|
937
|
+
)
|
|
938
|
+
tableRowStyle: TableRowStyleWritable = Field(
|
|
939
|
+
...,
|
|
940
|
+
title="The styles to be set on the rows.",
|
|
941
|
+
)
|
|
942
|
+
# TODO: Create a UpdateTableRowStyleFields enum to reduce LLM hallucinations.
|
|
943
|
+
# See UpdateTextStyleRequest for an example.
|
|
944
|
+
fields: str = Field(
|
|
945
|
+
...,
|
|
946
|
+
title=(
|
|
947
|
+
"The fields that should be updated. At least one field must be specified. The root "
|
|
948
|
+
"tableRowStyle is implied and should not be specified. A single '*' can be used as "
|
|
949
|
+
"short-hand for listing every field. For example to update the minimum row height, "
|
|
950
|
+
"set fields to 'minRowHeight'."
|
|
951
|
+
),
|
|
952
|
+
)
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
class ImageReplaceMethod(str, Enum):
|
|
956
|
+
CENTER_CROP = "CENTER_CROP"
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
class ReplaceImageRequest(BaseModel):
|
|
960
|
+
model_config = ConfigDict(title="Replaces an existing image with a new image.")
|
|
961
|
+
imageObjectId: str = Field(
|
|
962
|
+
...,
|
|
963
|
+
title=(
|
|
964
|
+
"The ID of the existing image that will be replaced. The ID can be retrieved from a "
|
|
965
|
+
"get response."
|
|
966
|
+
),
|
|
967
|
+
)
|
|
968
|
+
uri: str = Field(
|
|
969
|
+
...,
|
|
970
|
+
title=(
|
|
971
|
+
"The URI of the new image. Must be publicly accessible and <= 2 kB. Images must be < "
|
|
972
|
+
"50MB, <= 25 megapixels, and in PNG, JPEG, or GIF format."
|
|
973
|
+
),
|
|
974
|
+
)
|
|
975
|
+
imageReplaceMethod: ImageReplaceMethod = Field(ImageReplaceMethod.CENTER_CROP)
|
|
976
|
+
tabId: str | None = Field(
|
|
977
|
+
None,
|
|
978
|
+
title=(
|
|
979
|
+
"The tab that the image to be replaced is in. When omitted, the request applies to the "
|
|
980
|
+
"first tab."
|
|
981
|
+
),
|
|
982
|
+
)
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
class UpdateDocumentStyleRequest(BaseModel):
|
|
986
|
+
model_config = ConfigDict(title="Updates the DocumentStyle.")
|
|
987
|
+
documentStyle: DocumentStyleWritable = Field(
|
|
988
|
+
...,
|
|
989
|
+
title=(
|
|
990
|
+
"The styles to set on the document. Certain style changes may cause other changes to "
|
|
991
|
+
"mirror Docs editor behavior. See DocumentStyle docs for details."
|
|
992
|
+
),
|
|
993
|
+
)
|
|
994
|
+
# TODO: Create a UpdateDocumentStyleFields enum to reduce LLM hallucinations.
|
|
995
|
+
# See UpdateTextStyleRequest for an example.
|
|
996
|
+
fields: str = Field(
|
|
997
|
+
...,
|
|
998
|
+
title=(
|
|
999
|
+
"The fields that should be updated. At least one field must be specified. The root "
|
|
1000
|
+
"documentStyle is implied and should not be specified. A single '*' can be used as "
|
|
1001
|
+
"short-hand for listing every field. For example to update the background, set fields "
|
|
1002
|
+
"to 'background'."
|
|
1003
|
+
),
|
|
1004
|
+
)
|
|
1005
|
+
tabId: str | None = Field(
|
|
1006
|
+
None,
|
|
1007
|
+
title=(
|
|
1008
|
+
"The tab that contains the style to update. When omitted, the request applies to the "
|
|
1009
|
+
"first tab."
|
|
1010
|
+
),
|
|
1011
|
+
)
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
class MergeTableCellsRequest(BaseModel):
|
|
1015
|
+
model_config = ConfigDict(title="Merges cells in a Table.")
|
|
1016
|
+
tableRange: TableRange = Field(
|
|
1017
|
+
...,
|
|
1018
|
+
title=(
|
|
1019
|
+
"The table range specifying which cells of the table to merge. Text is concatenated "
|
|
1020
|
+
"into the 'head' cell of the range. The 'head' cell is the upper-left cell of the "
|
|
1021
|
+
"range when the content direction is left to right, and the upper-right cell "
|
|
1022
|
+
"of the range otherwise."
|
|
1023
|
+
),
|
|
1024
|
+
)
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
class UnmergeTableCellsRequest(BaseModel):
|
|
1028
|
+
model_config = ConfigDict(title="Unmerges cells in a Table.")
|
|
1029
|
+
tableRange: TableRange = Field(
|
|
1030
|
+
...,
|
|
1031
|
+
title=(
|
|
1032
|
+
"The table range specifying which cells of the table to unmerge. If there is text in "
|
|
1033
|
+
"any of the merged cells, the text will remain in the 'head' cell of the resulting "
|
|
1034
|
+
"block of unmerged cells. The 'head' cell is the upper-left cell when the content "
|
|
1035
|
+
"direction is from left to right, and the upper-right otherwise."
|
|
1036
|
+
),
|
|
1037
|
+
)
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
class CreateHeaderRequest(BaseModel):
|
|
1041
|
+
model_config = ConfigDict(title="Creates a Header.")
|
|
1042
|
+
type: HeaderFooterType = Field(
|
|
1043
|
+
...,
|
|
1044
|
+
title="The type of header to create.",
|
|
1045
|
+
)
|
|
1046
|
+
sectionBreakLocation: Location | None = Field(
|
|
1047
|
+
None,
|
|
1048
|
+
title=(
|
|
1049
|
+
"The location of the SectionBreak which begins the section "
|
|
1050
|
+
"this header should belong to. "
|
|
1051
|
+
"If unset or if it refers to the first section break in the document body, the header "
|
|
1052
|
+
"applies to the DocumentStyle."
|
|
1053
|
+
),
|
|
1054
|
+
)
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
class HeaderFooterType(str, Enum):
|
|
1058
|
+
HEADER_FOOTER_TYPE_UNSPECIFIED = "HEADER_FOOTER_TYPE_UNSPECIFIED"
|
|
1059
|
+
DEFAULT = "DEFAULT"
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
class CreateFooterRequest(BaseModel):
|
|
1063
|
+
model_config = ConfigDict(title="Creates a Footer.")
|
|
1064
|
+
type: HeaderFooterType = Field(
|
|
1065
|
+
...,
|
|
1066
|
+
title="The type of footer to create.",
|
|
1067
|
+
)
|
|
1068
|
+
sectionBreakLocation: Location | None = Field(
|
|
1069
|
+
None,
|
|
1070
|
+
title=(
|
|
1071
|
+
"The location of the SectionBreak immediately preceding the section whose SectionStyle "
|
|
1072
|
+
"this footer should belong to. If unset or refers to the first section break in the "
|
|
1073
|
+
"document, the footer applies to the DocumentStyle."
|
|
1074
|
+
),
|
|
1075
|
+
)
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
class CreateFootnoteRequest(BaseModel):
|
|
1079
|
+
model_config = ConfigDict(
|
|
1080
|
+
title=(
|
|
1081
|
+
"Creates a Footnote segment and inserts a new FootnoteReference to it at the given "
|
|
1082
|
+
"location. The new Footnote segment will contain a space followed by a newline."
|
|
1083
|
+
)
|
|
1084
|
+
)
|
|
1085
|
+
footnote_reference_location: Location | EndOfSegmentLocation = Field(
|
|
1086
|
+
...,
|
|
1087
|
+
title=(
|
|
1088
|
+
"Union field footnote_reference_location. "
|
|
1089
|
+
"The location to insert the footnote reference. "
|
|
1090
|
+
"location — Inserts at a specific index inside an existing Paragraph; cannot be inside "
|
|
1091
|
+
"a table's start index. Footnote references cannot be inside an equation, header, "
|
|
1092
|
+
"footer or footnote. Segment ID must be empty (body only). "
|
|
1093
|
+
"endOfSegmentLocation — Inserts at the end of the document body; cannot be inside a "
|
|
1094
|
+
"header, footer or footnote. Segment ID must be empty (body only)."
|
|
1095
|
+
),
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1098
|
+
@model_serializer(mode="wrap")
|
|
1099
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
1100
|
+
"""
|
|
1101
|
+
Modify/wraps the result of the handler to resolve the union field
|
|
1102
|
+
footnote_reference_location.
|
|
1103
|
+
|
|
1104
|
+
Args:
|
|
1105
|
+
handler: The handler function that would normally return the model's data
|
|
1106
|
+
such as `model_dump` or `model_json_schema`.
|
|
1107
|
+
|
|
1108
|
+
Returns:
|
|
1109
|
+
The modified data with the union field resolved.
|
|
1110
|
+
"""
|
|
1111
|
+
data = handler(self)
|
|
1112
|
+
data.pop("footnote_reference_location", None)
|
|
1113
|
+
if isinstance(self.footnote_reference_location, Location):
|
|
1114
|
+
data["location"] = self.footnote_reference_location.model_dump(exclude_none=True)
|
|
1115
|
+
elif isinstance(self.footnote_reference_location, EndOfSegmentLocation):
|
|
1116
|
+
data["endOfSegmentLocation"] = self.footnote_reference_location.model_dump(
|
|
1117
|
+
exclude_none=True
|
|
1118
|
+
)
|
|
1119
|
+
return data
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
class ReplaceNamedRangeContentRequest(BaseModel):
|
|
1123
|
+
model_config = ConfigDict(
|
|
1124
|
+
title=(
|
|
1125
|
+
"Replaces the contents of the specified NamedRange or NamedRanges with the given "
|
|
1126
|
+
"replacement content. For NamedRanges with multiple discontinuous ranges, only the "
|
|
1127
|
+
"first is replaced; others are deleted."
|
|
1128
|
+
)
|
|
1129
|
+
)
|
|
1130
|
+
tabsCriteria: TabsCriteria | None = Field(
|
|
1131
|
+
None,
|
|
1132
|
+
title=(
|
|
1133
|
+
"Optional. The criteria used to specify in which tabs the replacement occurs. When "
|
|
1134
|
+
"omitted, the replacement applies to all tabs."
|
|
1135
|
+
),
|
|
1136
|
+
)
|
|
1137
|
+
text: str = Field(
|
|
1138
|
+
...,
|
|
1139
|
+
title=("Replaces the content of the specified named range(s) with the given text."),
|
|
1140
|
+
)
|
|
1141
|
+
|
|
1142
|
+
class NamedRangeIdRef(BaseModel):
|
|
1143
|
+
namedRangeId: str = Field(
|
|
1144
|
+
...,
|
|
1145
|
+
title="The ID of the named range whose content will be replaced.",
|
|
1146
|
+
)
|
|
1147
|
+
|
|
1148
|
+
class NamedRangeNameRef(BaseModel):
|
|
1149
|
+
namedRangeName: str = Field(
|
|
1150
|
+
...,
|
|
1151
|
+
title=(
|
|
1152
|
+
"The name of the NamedRanges whose content will be replaced. "
|
|
1153
|
+
"Multiple ranges with the same name will all be replaced; "
|
|
1154
|
+
"if none exist, the request is a no-op."
|
|
1155
|
+
),
|
|
1156
|
+
)
|
|
1157
|
+
|
|
1158
|
+
named_range_reference: NamedRangeIdRef | NamedRangeNameRef = Field(
|
|
1159
|
+
...,
|
|
1160
|
+
title=(
|
|
1161
|
+
"Union field named_range_reference. "
|
|
1162
|
+
"A reference to the named range(s) whose content will be replaced. "
|
|
1163
|
+
"Exactly one of the following must be set: namedRangeId or namedRangeName."
|
|
1164
|
+
),
|
|
1165
|
+
)
|
|
1166
|
+
|
|
1167
|
+
@model_serializer(mode="wrap")
|
|
1168
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
1169
|
+
"""
|
|
1170
|
+
Modify/wraps the result of the handler to resolve the union field named_range_reference
|
|
1171
|
+
|
|
1172
|
+
Args:
|
|
1173
|
+
handler: The handler function that would normally return the model's data
|
|
1174
|
+
such as `model_dump` or `model_json_schema`.
|
|
1175
|
+
|
|
1176
|
+
Returns:
|
|
1177
|
+
The modified data with the union field resolved.
|
|
1178
|
+
"""
|
|
1179
|
+
data = handler(self)
|
|
1180
|
+
data.pop("named_range_reference", None)
|
|
1181
|
+
if isinstance(self.named_range_reference, ReplaceNamedRangeContentRequest.NamedRangeIdRef):
|
|
1182
|
+
data["namedRangeId"] = self.named_range_reference.namedRangeId
|
|
1183
|
+
elif isinstance(
|
|
1184
|
+
self.named_range_reference, ReplaceNamedRangeContentRequest.NamedRangeNameRef
|
|
1185
|
+
):
|
|
1186
|
+
data["namedRangeName"] = self.named_range_reference.namedRangeName
|
|
1187
|
+
return data
|
|
1188
|
+
|
|
1189
|
+
|
|
1190
|
+
class UpdateSectionStyleRequest(BaseModel):
|
|
1191
|
+
model_config = ConfigDict(title="Updates the SectionStyle.")
|
|
1192
|
+
range: RangeWritable = Field(
|
|
1193
|
+
...,
|
|
1194
|
+
title=(
|
|
1195
|
+
"The range overlapping the sections to style. Because section breaks can only be "
|
|
1196
|
+
"inserted inside the body, the segment ID field must be empty."
|
|
1197
|
+
),
|
|
1198
|
+
)
|
|
1199
|
+
sectionStyle: SectionStyleWritable = Field(
|
|
1200
|
+
...,
|
|
1201
|
+
title=(
|
|
1202
|
+
"The styles to be set on the section. Certain section style changes may cause other "
|
|
1203
|
+
"changes to mirror Docs editor behavior. See SectionStyle docs for more information."
|
|
1204
|
+
),
|
|
1205
|
+
)
|
|
1206
|
+
# TODO: Create a UpdateSectionStyleFields enum to reduce LLM hallucinations.
|
|
1207
|
+
# See UpdateTextStyleRequest for an example.
|
|
1208
|
+
fields: str = Field(
|
|
1209
|
+
...,
|
|
1210
|
+
title=(
|
|
1211
|
+
"The fields that should be updated. At least one field must be specified. The root "
|
|
1212
|
+
"sectionStyle is implied and must not be specified. A single '*' can be used as "
|
|
1213
|
+
"short-hand for listing every field. For example to update the left margin, set fields "
|
|
1214
|
+
"to 'marginLeft'."
|
|
1215
|
+
),
|
|
1216
|
+
)
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
class InsertSectionBreakRequest(BaseModel):
|
|
1220
|
+
model_config = ConfigDict(
|
|
1221
|
+
title=(
|
|
1222
|
+
"Inserts a section break at the given location. A newline character will be inserted "
|
|
1223
|
+
"before the section break."
|
|
1224
|
+
)
|
|
1225
|
+
)
|
|
1226
|
+
sectionType: SectionType = Field(
|
|
1227
|
+
...,
|
|
1228
|
+
title="The type of section to insert.",
|
|
1229
|
+
)
|
|
1230
|
+
insertion_location: Location | EndOfSegmentLocation = Field(
|
|
1231
|
+
...,
|
|
1232
|
+
title=(
|
|
1233
|
+
"Union field insertion_location. The location where the break will be inserted. "
|
|
1234
|
+
"location — Inserts a newline and a section break at a specific index inside an "
|
|
1235
|
+
"existing Paragraph; cannot be at a table's start index. Section breaks cannot be "
|
|
1236
|
+
"inside a table, equation, footnote, header, or footer. Segment ID must be empty "
|
|
1237
|
+
"(body only). "
|
|
1238
|
+
"endOfSegmentLocation — Inserts a newline and a section break at the end of the "
|
|
1239
|
+
"document body; cannot be inside a footnote, header or footer. Segment ID must be "
|
|
1240
|
+
"empty (body only)."
|
|
1241
|
+
),
|
|
1242
|
+
)
|
|
1243
|
+
|
|
1244
|
+
@model_serializer(mode="wrap")
|
|
1245
|
+
def _resolve_union_field(self, handler: Callable[[Any], Any]) -> Any:
|
|
1246
|
+
"""
|
|
1247
|
+
Modify/wraps the result of the handler to resolve the union field insertion_location
|
|
1248
|
+
|
|
1249
|
+
Args:
|
|
1250
|
+
handler: The handler function that would normally return the model's data
|
|
1251
|
+
such as `model_dump` or `model_json_schema`.
|
|
1252
|
+
|
|
1253
|
+
Returns:
|
|
1254
|
+
The modified data with the union field resolved.
|
|
1255
|
+
"""
|
|
1256
|
+
data = handler(self)
|
|
1257
|
+
data.pop("insertion_location", None)
|
|
1258
|
+
if isinstance(self.insertion_location, Location):
|
|
1259
|
+
data["location"] = self.insertion_location.model_dump(exclude_none=True)
|
|
1260
|
+
elif isinstance(self.insertion_location, EndOfSegmentLocation):
|
|
1261
|
+
data["endOfSegmentLocation"] = self.insertion_location.model_dump(exclude_none=True)
|
|
1262
|
+
return data
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
class DeleteHeaderRequest(BaseModel):
|
|
1266
|
+
model_config = ConfigDict(title="Deletes a Header from the document.")
|
|
1267
|
+
headerId: str = Field(
|
|
1268
|
+
...,
|
|
1269
|
+
title=(
|
|
1270
|
+
"The id of the header to delete. If defined on DocumentStyle, "
|
|
1271
|
+
"the reference is removed, resulting in no header of that type for the first section. "
|
|
1272
|
+
"If defined on a SectionStyle, the reference is removed and the header of that type is "
|
|
1273
|
+
"continued from the previous section."
|
|
1274
|
+
),
|
|
1275
|
+
)
|
|
1276
|
+
tabId: str | None = Field(
|
|
1277
|
+
None,
|
|
1278
|
+
title=(
|
|
1279
|
+
"The tab containing the header to delete. When omitted, the request applies to the "
|
|
1280
|
+
"first tab."
|
|
1281
|
+
),
|
|
1282
|
+
)
|
|
1283
|
+
|
|
1284
|
+
|
|
1285
|
+
class DeleteFooterRequest(BaseModel):
|
|
1286
|
+
model_config = ConfigDict(title="Deletes a Footer from the document.")
|
|
1287
|
+
footerId: str = Field(
|
|
1288
|
+
...,
|
|
1289
|
+
title=(
|
|
1290
|
+
"The id of the footer to delete. If defined on DocumentStyle, the reference is "
|
|
1291
|
+
"removed, resulting in no footer of that type for the first section. If defined on "
|
|
1292
|
+
"a SectionStyle, the reference is removed and the footer of that type is continued "
|
|
1293
|
+
"from the previous section."
|
|
1294
|
+
),
|
|
1295
|
+
)
|
|
1296
|
+
tabId: str | None = Field(
|
|
1297
|
+
None,
|
|
1298
|
+
title=(
|
|
1299
|
+
"The tab that contains the footer to delete. When omitted, the request applies to the "
|
|
1300
|
+
"first tab."
|
|
1301
|
+
),
|
|
1302
|
+
)
|
|
1303
|
+
|
|
1304
|
+
|
|
1305
|
+
class PinTableHeaderRowsRequest(BaseModel):
|
|
1306
|
+
model_config = ConfigDict(title="Updates the number of pinned table header rows in a table.")
|
|
1307
|
+
tableStartLocation: Location = Field(
|
|
1308
|
+
...,
|
|
1309
|
+
title="The location where the table starts in the document.",
|
|
1310
|
+
)
|
|
1311
|
+
pinnedHeaderRowsCount: int = Field(
|
|
1312
|
+
...,
|
|
1313
|
+
ge=0,
|
|
1314
|
+
title=("The number of table rows to pin, where 0 implies that all rows are unpinned."),
|
|
1315
|
+
)
|