gsuite-sdk 0.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.
- gsuite_calendar/__init__.py +13 -0
- gsuite_calendar/calendar_entity.py +31 -0
- gsuite_calendar/client.py +268 -0
- gsuite_calendar/event.py +57 -0
- gsuite_calendar/parser.py +119 -0
- gsuite_calendar/py.typed +0 -0
- gsuite_core/__init__.py +62 -0
- gsuite_core/api_utils.py +167 -0
- gsuite_core/auth/__init__.py +6 -0
- gsuite_core/auth/oauth.py +249 -0
- gsuite_core/auth/scopes.py +84 -0
- gsuite_core/config.py +73 -0
- gsuite_core/exceptions.py +125 -0
- gsuite_core/py.typed +0 -0
- gsuite_core/storage/__init__.py +13 -0
- gsuite_core/storage/base.py +65 -0
- gsuite_core/storage/secretmanager.py +141 -0
- gsuite_core/storage/sqlite.py +79 -0
- gsuite_drive/__init__.py +12 -0
- gsuite_drive/client.py +401 -0
- gsuite_drive/file.py +103 -0
- gsuite_drive/parser.py +66 -0
- gsuite_drive/py.typed +0 -0
- gsuite_gmail/__init__.py +17 -0
- gsuite_gmail/client.py +412 -0
- gsuite_gmail/label.py +56 -0
- gsuite_gmail/message.py +211 -0
- gsuite_gmail/parser.py +155 -0
- gsuite_gmail/py.typed +0 -0
- gsuite_gmail/query.py +227 -0
- gsuite_gmail/thread.py +54 -0
- gsuite_sdk-0.1.0.dist-info/METADATA +384 -0
- gsuite_sdk-0.1.0.dist-info/RECORD +42 -0
- gsuite_sdk-0.1.0.dist-info/WHEEL +5 -0
- gsuite_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
- gsuite_sdk-0.1.0.dist-info/top_level.txt +5 -0
- gsuite_sheets/__init__.py +13 -0
- gsuite_sheets/client.py +375 -0
- gsuite_sheets/parser.py +76 -0
- gsuite_sheets/py.typed +0 -0
- gsuite_sheets/spreadsheet.py +97 -0
- gsuite_sheets/worksheet.py +185 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Worksheet entity."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from gsuite_sheets.spreadsheet import Spreadsheet
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class Worksheet:
|
|
12
|
+
"""
|
|
13
|
+
A worksheet (tab) within a spreadsheet.
|
|
14
|
+
|
|
15
|
+
Provides methods for reading and writing cell data.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
id: int
|
|
19
|
+
title: str
|
|
20
|
+
index: int
|
|
21
|
+
row_count: int = 1000
|
|
22
|
+
column_count: int = 26
|
|
23
|
+
|
|
24
|
+
_spreadsheet: Optional["Spreadsheet"] = field(default=None, repr=False)
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def url(self) -> str | None:
|
|
28
|
+
"""Get URL to this specific worksheet."""
|
|
29
|
+
if self._spreadsheet:
|
|
30
|
+
return f"{self._spreadsheet.url}#gid={self.id}"
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
# ========== Reading ==========
|
|
34
|
+
|
|
35
|
+
def get(self, range: str = "A1") -> list[list[Any]]:
|
|
36
|
+
"""
|
|
37
|
+
Get values from a range.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
range: A1 notation (e.g., "A1:B10", "A:C", "1:5")
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
2D list of values
|
|
44
|
+
"""
|
|
45
|
+
if not self._spreadsheet:
|
|
46
|
+
raise RuntimeError("Worksheet not linked to spreadsheet")
|
|
47
|
+
return self._spreadsheet._sheets.get_values(self._spreadsheet.id, f"{self.title}!{range}")
|
|
48
|
+
|
|
49
|
+
def get_all_values(self) -> list[list[Any]]:
|
|
50
|
+
"""Get all values in the worksheet."""
|
|
51
|
+
return self.get("A1:ZZ")
|
|
52
|
+
|
|
53
|
+
def get_all_records(self, head: int = 1) -> list[dict]:
|
|
54
|
+
"""
|
|
55
|
+
Get all rows as list of dicts using row as headers.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
head: Row number to use as headers (1-indexed)
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
List of dicts with header keys
|
|
62
|
+
"""
|
|
63
|
+
values = self.get_all_values()
|
|
64
|
+
if len(values) < head:
|
|
65
|
+
return []
|
|
66
|
+
|
|
67
|
+
headers = values[head - 1]
|
|
68
|
+
records = []
|
|
69
|
+
|
|
70
|
+
for row in values[head:]:
|
|
71
|
+
# Pad row to match headers length
|
|
72
|
+
padded = row + [""] * (len(headers) - len(row))
|
|
73
|
+
record = dict(zip(headers, padded))
|
|
74
|
+
records.append(record)
|
|
75
|
+
|
|
76
|
+
return records
|
|
77
|
+
|
|
78
|
+
def row_values(self, row: int) -> list[Any]:
|
|
79
|
+
"""Get all values in a row (1-indexed)."""
|
|
80
|
+
values = self.get(f"{row}:{row}")
|
|
81
|
+
return values[0] if values else []
|
|
82
|
+
|
|
83
|
+
def col_values(self, col: int) -> list[Any]:
|
|
84
|
+
"""Get all values in a column (1-indexed)."""
|
|
85
|
+
col_letter = self._col_to_letter(col)
|
|
86
|
+
values = self.get(f"{col_letter}:{col_letter}")
|
|
87
|
+
return [row[0] if row else "" for row in values]
|
|
88
|
+
|
|
89
|
+
def cell(self, row: int, col: int) -> Any:
|
|
90
|
+
"""Get a single cell value (1-indexed)."""
|
|
91
|
+
col_letter = self._col_to_letter(col)
|
|
92
|
+
values = self.get(f"{col_letter}{row}")
|
|
93
|
+
if values and values[0]:
|
|
94
|
+
return values[0][0]
|
|
95
|
+
return ""
|
|
96
|
+
|
|
97
|
+
# ========== Writing ==========
|
|
98
|
+
|
|
99
|
+
def update(self, range: str, values: list[list[Any]]) -> dict:
|
|
100
|
+
"""
|
|
101
|
+
Update a range with values.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
range: A1 notation
|
|
105
|
+
values: 2D list of values
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Update response
|
|
109
|
+
"""
|
|
110
|
+
if not self._spreadsheet:
|
|
111
|
+
raise RuntimeError("Worksheet not linked to spreadsheet")
|
|
112
|
+
return self._spreadsheet._sheets.update_values(
|
|
113
|
+
self._spreadsheet.id, f"{self.title}!{range}", values
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def update_cell(self, row: int, col: int, value: Any) -> dict:
|
|
117
|
+
"""Update a single cell (1-indexed)."""
|
|
118
|
+
col_letter = self._col_to_letter(col)
|
|
119
|
+
return self.update(f"{col_letter}{row}", [[value]])
|
|
120
|
+
|
|
121
|
+
def append_row(self, values: list[Any]) -> dict:
|
|
122
|
+
"""Append a row to the end of the worksheet."""
|
|
123
|
+
if not self._spreadsheet:
|
|
124
|
+
raise RuntimeError("Worksheet not linked to spreadsheet")
|
|
125
|
+
return self._spreadsheet._sheets.append_values(
|
|
126
|
+
self._spreadsheet.id, f"{self.title}!A1", [values]
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def append_rows(self, rows: list[list[Any]]) -> dict:
|
|
130
|
+
"""Append multiple rows."""
|
|
131
|
+
if not self._spreadsheet:
|
|
132
|
+
raise RuntimeError("Worksheet not linked to spreadsheet")
|
|
133
|
+
return self._spreadsheet._sheets.append_values(
|
|
134
|
+
self._spreadsheet.id, f"{self.title}!A1", rows
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def clear(self, range: str | None = None) -> dict:
|
|
138
|
+
"""
|
|
139
|
+
Clear values from a range or entire worksheet.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
range: A1 notation (default: entire sheet)
|
|
143
|
+
"""
|
|
144
|
+
if not self._spreadsheet:
|
|
145
|
+
raise RuntimeError("Worksheet not linked to spreadsheet")
|
|
146
|
+
|
|
147
|
+
full_range = f"{self.title}!{range}" if range else self.title
|
|
148
|
+
return self._spreadsheet._sheets.clear_values(self._spreadsheet.id, full_range)
|
|
149
|
+
|
|
150
|
+
# ========== Search ==========
|
|
151
|
+
|
|
152
|
+
def find(self, query: str) -> tuple[int, int] | None:
|
|
153
|
+
"""
|
|
154
|
+
Find first cell containing query.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
(row, col) tuple or None
|
|
158
|
+
"""
|
|
159
|
+
values = self.get_all_values()
|
|
160
|
+
for row_idx, row in enumerate(values):
|
|
161
|
+
for col_idx, cell in enumerate(row):
|
|
162
|
+
if str(cell) == query:
|
|
163
|
+
return (row_idx + 1, col_idx + 1)
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def findall(self, query: str) -> list[tuple[int, int]]:
|
|
167
|
+
"""Find all cells containing query."""
|
|
168
|
+
values = self.get_all_values()
|
|
169
|
+
results = []
|
|
170
|
+
for row_idx, row in enumerate(values):
|
|
171
|
+
for col_idx, cell in enumerate(row):
|
|
172
|
+
if str(cell) == query:
|
|
173
|
+
results.append((row_idx + 1, col_idx + 1))
|
|
174
|
+
return results
|
|
175
|
+
|
|
176
|
+
# ========== Helpers ==========
|
|
177
|
+
|
|
178
|
+
@staticmethod
|
|
179
|
+
def _col_to_letter(col: int) -> str:
|
|
180
|
+
"""Convert column number to letter (1=A, 27=AA)."""
|
|
181
|
+
result = ""
|
|
182
|
+
while col > 0:
|
|
183
|
+
col, remainder = divmod(col - 1, 26)
|
|
184
|
+
result = chr(65 + remainder) + result
|
|
185
|
+
return result
|