arcade-google 0.1.0__py3-none-any.whl → 0.1.2__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/tools/gmail.py +137 -25
- arcade_google/tools/models.py +3 -1
- arcade_google/tools/utils.py +10 -8
- {arcade_google-0.1.0.dist-info → arcade_google-0.1.2.dist-info}/METADATA +2 -2
- arcade_google-0.1.2.dist-info/RECORD +11 -0
- arcade_google-0.1.0.dist-info/RECORD +0 -11
- {arcade_google-0.1.0.dist-info → arcade_google-0.1.2.dist-info}/WHEEL +0 -0
arcade_google/tools/gmail.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import base64
|
|
2
|
-
import json
|
|
3
2
|
from email.message import EmailMessage
|
|
4
3
|
from email.mime.text import MIMEText
|
|
5
4
|
from typing import Annotated, Optional
|
|
@@ -20,6 +19,7 @@ from arcade_google.tools.utils import (
|
|
|
20
19
|
get_sent_email_url,
|
|
21
20
|
parse_draft_email,
|
|
22
21
|
parse_email,
|
|
22
|
+
remove_none_values,
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
|
@@ -36,7 +36,7 @@ async def send_email(
|
|
|
36
36
|
recipient: Annotated[str, "The recipient of the email"],
|
|
37
37
|
cc: Annotated[Optional[list[str]], "CC recipients of the email"] = None,
|
|
38
38
|
bcc: Annotated[Optional[list[str]], "BCC recipients of the email"] = None,
|
|
39
|
-
) -> Annotated[
|
|
39
|
+
) -> Annotated[dict, "A dictionary containing the sent email details"]:
|
|
40
40
|
"""
|
|
41
41
|
Send an email using the Gmail API.
|
|
42
42
|
"""
|
|
@@ -61,7 +61,10 @@ async def send_email(
|
|
|
61
61
|
|
|
62
62
|
# Send the email
|
|
63
63
|
sent_message = service.users().messages().send(userId="me", body=email).execute()
|
|
64
|
-
|
|
64
|
+
|
|
65
|
+
email = parse_email(sent_message)
|
|
66
|
+
email["url"] = get_sent_email_url(sent_message["id"])
|
|
67
|
+
return email
|
|
65
68
|
|
|
66
69
|
|
|
67
70
|
@tool(
|
|
@@ -71,7 +74,7 @@ async def send_email(
|
|
|
71
74
|
)
|
|
72
75
|
async def send_draft_email(
|
|
73
76
|
context: ToolContext, email_id: Annotated[str, "The ID of the draft to send"]
|
|
74
|
-
) -> Annotated[
|
|
77
|
+
) -> Annotated[dict, "A dictionary containing the sent email details"]:
|
|
75
78
|
"""
|
|
76
79
|
Send a draft email using the Gmail API.
|
|
77
80
|
"""
|
|
@@ -82,10 +85,9 @@ async def send_draft_email(
|
|
|
82
85
|
# Send the draft email
|
|
83
86
|
sent_message = service.users().drafts().send(userId="me", body={"id": email_id}).execute()
|
|
84
87
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
)
|
|
88
|
+
email = parse_email(sent_message)
|
|
89
|
+
email["url"] = get_sent_email_url(sent_message["id"])
|
|
90
|
+
return email
|
|
89
91
|
|
|
90
92
|
|
|
91
93
|
# Draft Management Tools
|
|
@@ -101,7 +103,7 @@ async def write_draft_email(
|
|
|
101
103
|
recipient: Annotated[str, "The recipient of the draft email"],
|
|
102
104
|
cc: Annotated[Optional[list[str]], "CC recipients of the draft email"] = None,
|
|
103
105
|
bcc: Annotated[Optional[list[str]], "BCC recipients of the draft email"] = None,
|
|
104
|
-
) -> Annotated[
|
|
106
|
+
) -> Annotated[dict, "A dictionary containing the created draft email details"]:
|
|
105
107
|
"""
|
|
106
108
|
Compose a new email draft using the Gmail API.
|
|
107
109
|
"""
|
|
@@ -123,9 +125,9 @@ async def write_draft_email(
|
|
|
123
125
|
draft = {"message": {"raw": raw_message}}
|
|
124
126
|
|
|
125
127
|
draft_message = service.users().drafts().create(userId="me", body=draft).execute()
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
email = parse_draft_email(draft_message)
|
|
129
|
+
email["url"] = get_draft_url(draft_message["id"])
|
|
130
|
+
return email
|
|
129
131
|
|
|
130
132
|
|
|
131
133
|
@tool(
|
|
@@ -141,7 +143,7 @@ async def update_draft_email(
|
|
|
141
143
|
recipient: Annotated[str, "The recipient of the draft email"],
|
|
142
144
|
cc: Annotated[Optional[list[str]], "CC recipients of the draft email"] = None,
|
|
143
145
|
bcc: Annotated[Optional[list[str]], "BCC recipients of the draft email"] = None,
|
|
144
|
-
) -> Annotated[
|
|
146
|
+
) -> Annotated[dict, "A dictionary containing the updated draft email details"]:
|
|
145
147
|
"""
|
|
146
148
|
Update an existing email draft using the Gmail API.
|
|
147
149
|
"""
|
|
@@ -166,7 +168,10 @@ async def update_draft_email(
|
|
|
166
168
|
updated_draft_message = (
|
|
167
169
|
service.users().drafts().update(userId="me", id=draft_email_id, body=draft).execute()
|
|
168
170
|
)
|
|
169
|
-
|
|
171
|
+
|
|
172
|
+
email = parse_draft_email(updated_draft_message)
|
|
173
|
+
email["url"] = get_draft_url(updated_draft_message["id"])
|
|
174
|
+
return email
|
|
170
175
|
|
|
171
176
|
|
|
172
177
|
@tool(
|
|
@@ -198,7 +203,7 @@ async def delete_draft_email(
|
|
|
198
203
|
)
|
|
199
204
|
async def trash_email(
|
|
200
205
|
context: ToolContext, email_id: Annotated[str, "The ID of the email to trash"]
|
|
201
|
-
) -> Annotated[
|
|
206
|
+
) -> Annotated[dict, "A dictionary containing the trashed email details"]:
|
|
202
207
|
"""
|
|
203
208
|
Move an email to the trash folder using the Gmail API.
|
|
204
209
|
"""
|
|
@@ -207,9 +212,11 @@ async def trash_email(
|
|
|
207
212
|
service = build("gmail", "v1", credentials=Credentials(context.authorization.token))
|
|
208
213
|
|
|
209
214
|
# Trash the email
|
|
210
|
-
service.users().messages().trash(userId="me", id=email_id).execute()
|
|
215
|
+
trashed_email = service.users().messages().trash(userId="me", id=email_id).execute()
|
|
211
216
|
|
|
212
|
-
|
|
217
|
+
email = parse_email(trashed_email)
|
|
218
|
+
email["url"] = get_email_in_trash_url(trashed_email["id"])
|
|
219
|
+
return email
|
|
213
220
|
|
|
214
221
|
|
|
215
222
|
# Draft Search Tools
|
|
@@ -221,7 +228,7 @@ async def trash_email(
|
|
|
221
228
|
async def list_draft_emails(
|
|
222
229
|
context: ToolContext,
|
|
223
230
|
n_drafts: Annotated[int, "Number of draft emails to read"] = 5,
|
|
224
|
-
) -> Annotated[
|
|
231
|
+
) -> Annotated[dict, "A dictionary containing a list of draft email details"]:
|
|
225
232
|
"""
|
|
226
233
|
Lists draft emails in the user's draft mailbox using the Gmail API.
|
|
227
234
|
"""
|
|
@@ -245,7 +252,7 @@ async def list_draft_emails(
|
|
|
245
252
|
except Exception as e:
|
|
246
253
|
print(f"Error reading draft email {draft_id}: {e}")
|
|
247
254
|
|
|
248
|
-
return
|
|
255
|
+
return {"emails": emails}
|
|
249
256
|
|
|
250
257
|
|
|
251
258
|
# Email Search Tools
|
|
@@ -263,11 +270,11 @@ async def list_emails_by_header(
|
|
|
263
270
|
date_range: Annotated[Optional[DateRange], "The date range of the email"] = None,
|
|
264
271
|
limit: Annotated[Optional[int], "The maximum number of emails to return"] = 25,
|
|
265
272
|
) -> Annotated[
|
|
266
|
-
|
|
273
|
+
dict, "A dictionary containing a list of email details matching the search criteria"
|
|
267
274
|
]:
|
|
268
275
|
"""
|
|
269
276
|
Search for emails by header using the Gmail API.
|
|
270
|
-
At least one of the following
|
|
277
|
+
At least one of the following parameters MUST be provided: sender, recipient, subject, body.
|
|
271
278
|
"""
|
|
272
279
|
if not any([sender, recipient, subject, body]):
|
|
273
280
|
raise RetryableToolError(
|
|
@@ -281,10 +288,10 @@ async def list_emails_by_header(
|
|
|
281
288
|
messages = fetch_messages(service, query, limit)
|
|
282
289
|
|
|
283
290
|
if not messages:
|
|
284
|
-
return
|
|
291
|
+
return {"emails": []}
|
|
285
292
|
|
|
286
293
|
emails = process_messages(service, messages)
|
|
287
|
-
return
|
|
294
|
+
return {"emails": emails}
|
|
288
295
|
|
|
289
296
|
|
|
290
297
|
def process_messages(service, messages):
|
|
@@ -307,7 +314,7 @@ def process_messages(service, messages):
|
|
|
307
314
|
async def list_emails(
|
|
308
315
|
context: ToolContext,
|
|
309
316
|
n_emails: Annotated[int, "Number of emails to read"] = 5,
|
|
310
|
-
) -> Annotated[
|
|
317
|
+
) -> Annotated[dict, "A dictionary containing a list of email details"]:
|
|
311
318
|
"""
|
|
312
319
|
Read emails from a Gmail account and extract plain text content.
|
|
313
320
|
"""
|
|
@@ -329,4 +336,109 @@ async def list_emails(
|
|
|
329
336
|
except Exception as e:
|
|
330
337
|
print(f"Error reading email {msg['id']}: {e}")
|
|
331
338
|
|
|
332
|
-
return
|
|
339
|
+
return {"emails": emails}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@tool(
|
|
343
|
+
requires_auth=Google(
|
|
344
|
+
scopes=["https://www.googleapis.com/auth/gmail.readonly"],
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
async def search_threads(
|
|
348
|
+
context: ToolContext,
|
|
349
|
+
page_token: Annotated[
|
|
350
|
+
Optional[str], "Page token to retrieve a specific page of results in the list"
|
|
351
|
+
] = None,
|
|
352
|
+
max_results: Annotated[int, "The maximum number of threads to return"] = 10,
|
|
353
|
+
include_spam_trash: Annotated[bool, "Whether to include spam and trash in the results"] = False,
|
|
354
|
+
label_ids: Annotated[Optional[list[str]], "The IDs of labels to filter by"] = None,
|
|
355
|
+
sender: Annotated[Optional[str], "The name or email address of the sender of the email"] = None,
|
|
356
|
+
recipient: Annotated[Optional[str], "The name or email address of the recipient"] = None,
|
|
357
|
+
subject: Annotated[Optional[str], "Words to find in the subject of the email"] = None,
|
|
358
|
+
body: Annotated[Optional[str], "Words to find in the body of the email"] = None,
|
|
359
|
+
date_range: Annotated[Optional[DateRange], "The date range of the email"] = None,
|
|
360
|
+
) -> Annotated[dict, "A dictionary containing a list of thread details"]:
|
|
361
|
+
"""Search for threads in the user's mailbox"""
|
|
362
|
+
service = build("gmail", "v1", credentials=Credentials(context.authorization.token))
|
|
363
|
+
|
|
364
|
+
query = (
|
|
365
|
+
build_query_string(sender, recipient, subject, body, date_range)
|
|
366
|
+
if any([sender, recipient, subject, body, date_range])
|
|
367
|
+
else None
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
params = {
|
|
371
|
+
"userId": "me",
|
|
372
|
+
"maxResults": min(max_results, 500),
|
|
373
|
+
"pageToken": page_token,
|
|
374
|
+
"includeSpamTrash": include_spam_trash,
|
|
375
|
+
"labelIds": label_ids,
|
|
376
|
+
"q": query,
|
|
377
|
+
}
|
|
378
|
+
params = remove_none_values(params)
|
|
379
|
+
|
|
380
|
+
threads = []
|
|
381
|
+
next_page_token = None
|
|
382
|
+
# Paginate through thread pages until we have the desired number of threads
|
|
383
|
+
while len(threads) < max_results:
|
|
384
|
+
response = service.users().threads().list(**params).execute()
|
|
385
|
+
|
|
386
|
+
threads.extend(response.get("threads", []))
|
|
387
|
+
next_page_token = response.get("nextPageToken")
|
|
388
|
+
|
|
389
|
+
if not next_page_token:
|
|
390
|
+
break
|
|
391
|
+
|
|
392
|
+
params["pageToken"] = next_page_token
|
|
393
|
+
params["maxResults"] = min(max_results - len(threads), 500)
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
"threads": threads,
|
|
397
|
+
"num_threads": len(threads),
|
|
398
|
+
"next_page_token": next_page_token,
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
@tool(
|
|
403
|
+
requires_auth=Google(
|
|
404
|
+
scopes=["https://www.googleapis.com/auth/gmail.readonly"],
|
|
405
|
+
)
|
|
406
|
+
)
|
|
407
|
+
async def list_threads(
|
|
408
|
+
context: ToolContext,
|
|
409
|
+
page_token: Annotated[
|
|
410
|
+
Optional[str], "Page token to retrieve a specific page of results in the list"
|
|
411
|
+
] = None,
|
|
412
|
+
max_results: Annotated[int, "The maximum number of threads to return"] = 10,
|
|
413
|
+
include_spam_trash: Annotated[bool, "Whether to include spam and trash in the results"] = False,
|
|
414
|
+
) -> Annotated[dict, "A dictionary containing a list of thread details"]:
|
|
415
|
+
"""List threads in the user's mailbox."""
|
|
416
|
+
return await search_threads(context, page_token, max_results, include_spam_trash)
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
@tool(
|
|
420
|
+
requires_auth=Google(
|
|
421
|
+
scopes=["https://www.googleapis.com/auth/gmail.readonly"],
|
|
422
|
+
)
|
|
423
|
+
)
|
|
424
|
+
async def get_thread(
|
|
425
|
+
context: ToolContext,
|
|
426
|
+
thread_id: Annotated[str, "The ID of the thread to retrieve"],
|
|
427
|
+
metadata_headers: Annotated[
|
|
428
|
+
Optional[list[str]], "When given and format is METADATA, only include headers specified."
|
|
429
|
+
] = None,
|
|
430
|
+
) -> Annotated[dict, "A dictionary containing the thread details"]:
|
|
431
|
+
"""Get the specified thread by ID."""
|
|
432
|
+
params = {
|
|
433
|
+
"userId": "me",
|
|
434
|
+
"id": thread_id,
|
|
435
|
+
"format": "full",
|
|
436
|
+
"metadataHeaders": metadata_headers,
|
|
437
|
+
}
|
|
438
|
+
params = remove_none_values(params)
|
|
439
|
+
|
|
440
|
+
service = build("gmail", "v1", credentials=Credentials(context.authorization.token))
|
|
441
|
+
thread = service.users().threads().get(**params).execute()
|
|
442
|
+
thread["messages"] = [parse_email(message) for message in thread.get("messages", [])]
|
|
443
|
+
|
|
444
|
+
return thread
|
arcade_google/tools/models.py
CHANGED
|
@@ -232,7 +232,9 @@ class SendUpdatesOptions(Enum):
|
|
|
232
232
|
EXTERNAL_ONLY = "externalOnly" # Notifications are sent to non-Google Calendar guests only.
|
|
233
233
|
|
|
234
234
|
|
|
235
|
-
#
|
|
235
|
+
# ---------------------------------------------------------------------------- #
|
|
236
|
+
# Google Drive Models and Enums
|
|
237
|
+
# ---------------------------------------------------------------------------- #
|
|
236
238
|
class Corpora(str, Enum):
|
|
237
239
|
"""
|
|
238
240
|
Bodies of items (files/documents) to which the query applies.
|
arcade_google/tools/utils.py
CHANGED
|
@@ -82,16 +82,17 @@ def parse_email(email_data: dict[str, Any]) -> Optional[dict[str, str]]:
|
|
|
82
82
|
Optional[Dict[str, str]]: Parsed email details or None if parsing fails.
|
|
83
83
|
"""
|
|
84
84
|
try:
|
|
85
|
-
payload = email_data
|
|
86
|
-
headers = {d["name"].lower(): d["value"] for d in payload
|
|
85
|
+
payload = email_data.get("payload", {})
|
|
86
|
+
headers = {d["name"].lower(): d["value"] for d in payload.get("headers", [])}
|
|
87
87
|
|
|
88
88
|
body_data = _get_email_body(payload)
|
|
89
89
|
|
|
90
90
|
return {
|
|
91
91
|
"id": email_data.get("id", ""),
|
|
92
|
+
"thread_id": email_data.get("threadId", ""),
|
|
92
93
|
"from": headers.get("from", ""),
|
|
93
94
|
"date": headers.get("date", ""),
|
|
94
|
-
"subject": headers.get("subject", "
|
|
95
|
+
"subject": headers.get("subject", ""),
|
|
95
96
|
"body": _clean_email_body(body_data) if body_data else "",
|
|
96
97
|
}
|
|
97
98
|
except Exception as e:
|
|
@@ -110,17 +111,18 @@ def parse_draft_email(draft_email_data: dict[str, Any]) -> Optional[dict[str, st
|
|
|
110
111
|
Optional[Dict[str, str]]: Parsed draft email details or None if parsing fails.
|
|
111
112
|
"""
|
|
112
113
|
try:
|
|
113
|
-
message = draft_email_data
|
|
114
|
-
payload = message
|
|
115
|
-
headers = {d["name"].lower(): d["value"] for d in payload
|
|
114
|
+
message = draft_email_data.get("message", {})
|
|
115
|
+
payload = message.get("payload", {})
|
|
116
|
+
headers = {d["name"].lower(): d["value"] for d in payload.get("headers", [])}
|
|
116
117
|
|
|
117
118
|
body_data = _get_email_body(payload)
|
|
118
119
|
|
|
119
120
|
return {
|
|
120
121
|
"id": draft_email_data.get("id", ""),
|
|
122
|
+
"thread_id": draft_email_data.get("threadId", ""),
|
|
121
123
|
"from": headers.get("from", ""),
|
|
122
124
|
"date": headers.get("internaldate", ""),
|
|
123
|
-
"subject": headers.get("subject", "
|
|
125
|
+
"subject": headers.get("subject", ""),
|
|
124
126
|
"body": _clean_email_body(body_data) if body_data else "",
|
|
125
127
|
}
|
|
126
128
|
except Exception as e:
|
|
@@ -226,7 +228,7 @@ def _update_datetime(day: Day | None, time: TimeSlot | None, time_zone: str) ->
|
|
|
226
228
|
|
|
227
229
|
def build_query_string(sender, recipient, subject, body, date_range):
|
|
228
230
|
"""
|
|
229
|
-
Helper function to build a query string for Gmail list_emails_by_header
|
|
231
|
+
Helper function to build a query string for Gmail list_emails_by_header and search_threads tools.
|
|
230
232
|
"""
|
|
231
233
|
query = []
|
|
232
234
|
if sender:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: arcade_google
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Arcade tools for the entire google suite
|
|
5
5
|
Author: Arcade AI
|
|
6
6
|
Author-email: dev@arcade-ai.com
|
|
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.11
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
-
Requires-Dist: arcade-ai (==0.1.
|
|
13
|
+
Requires-Dist: arcade-ai (==0.1.2)
|
|
14
14
|
Requires-Dist: beautifulsoup4 (>=4.10.0,<5.0.0)
|
|
15
15
|
Requires-Dist: google-api-core (==2.19.1)
|
|
16
16
|
Requires-Dist: google-api-python-client (==2.137.0)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
arcade_google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
arcade_google/tools/__init__.py,sha256=MXM0xOEislCvl1UgwJC_Nqme83KjkQsaiUj4VKP0Q9s,49
|
|
3
|
+
arcade_google/tools/calendar.py,sha256=kYK0Ff3gKnen3tXgOEIHemrnBqGsfHjJlbbYCXw_qxk,11751
|
|
4
|
+
arcade_google/tools/docs.py,sha256=n3SpfuGx4x6RH-uVc_h2_LgRJgTU11fFexSUYjM88Ps,5045
|
|
5
|
+
arcade_google/tools/drive.py,sha256=U7I8DrcMKV72JEowaKH6h-4ruBEAvgJNbjq9cepvLag,3213
|
|
6
|
+
arcade_google/tools/gmail.py,sha256=onmGkKy-S7kJAO4zgpbzwiLB_Z1hPy_mJHUNqNMoxRk,15249
|
|
7
|
+
arcade_google/tools/models.py,sha256=hKZIbkL0a3ddVFoV_NxiwUhNxVxXdlKK2K44TkCGnfA,9755
|
|
8
|
+
arcade_google/tools/utils.py,sha256=9gJil5G0ufX9OpkFfEqzWKb5AFI9HPm-SveVyGlOVro,8515
|
|
9
|
+
arcade_google-0.1.2.dist-info/METADATA,sha256=qRI1cabjnyqDLS-xH7iGXpp6AzTA7Wb7AWNTgwsN8Xc,796
|
|
10
|
+
arcade_google-0.1.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
11
|
+
arcade_google-0.1.2.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
arcade_google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
arcade_google/tools/__init__.py,sha256=MXM0xOEislCvl1UgwJC_Nqme83KjkQsaiUj4VKP0Q9s,49
|
|
3
|
-
arcade_google/tools/calendar.py,sha256=kYK0Ff3gKnen3tXgOEIHemrnBqGsfHjJlbbYCXw_qxk,11751
|
|
4
|
-
arcade_google/tools/docs.py,sha256=n3SpfuGx4x6RH-uVc_h2_LgRJgTU11fFexSUYjM88Ps,5045
|
|
5
|
-
arcade_google/tools/drive.py,sha256=U7I8DrcMKV72JEowaKH6h-4ruBEAvgJNbjq9cepvLag,3213
|
|
6
|
-
arcade_google/tools/gmail.py,sha256=9hBZ1r79LTagFbFZazjrcyr9UPnTBHmSDiGdInd52Fo,11392
|
|
7
|
-
arcade_google/tools/models.py,sha256=um8mKisitNPimCx1HYX9spnKp1UzBWfRF4H2ducGn-8,9592
|
|
8
|
-
arcade_google/tools/utils.py,sha256=jO9RpRm8N_NRhnGtpHDLKf_he1u2-3r8iSqR5JxaPfU,8355
|
|
9
|
-
arcade_google-0.1.0.dist-info/METADATA,sha256=lWKS5BLCD0e7shhCCVm7d9zGs_pN7SZs3_2hXEyzzH0,796
|
|
10
|
-
arcade_google-0.1.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
11
|
-
arcade_google-0.1.0.dist-info/RECORD,,
|
|
File without changes
|