notionhelper 0.1.0__tar.gz

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.
@@ -0,0 +1,10 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: notionhelper
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Author-email: Jan du Plessis <drjanduplessis@icloud.com>
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: httpx>=0.27.0
8
+ Requires-Dist: mimetype>=0.1.5
9
+ Requires-Dist: notion-client>=2.4.0
10
+ Requires-Dist: pandas>=2.3.1
File without changes
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "notionhelper"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Jan du Plessis", email = "drjanduplessis@icloud.com" }
8
+ ]
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "mimetype>=0.1.5",
12
+ "notion-client>=2.4.0",
13
+ "pandas>=2.3.1",
14
+ "httpx>=0.27.0",
15
+ ]
16
+
17
+ [build-system]
18
+ requires = ["hatchling"]
19
+ build-backend = "hatchling.build"
@@ -0,0 +1,2 @@
1
+ def hello() -> str:
2
+ return "Hello from notionhelper!"
@@ -0,0 +1,479 @@
1
+ import notion_client
2
+ from notion_client import AsyncClient
3
+ import pprint
4
+ import pandas as pd
5
+ import os
6
+ import httpx
7
+ import mimetypes
8
+ import os
9
+
10
+ # NotionHelper can be used in conjunction with the Streamlit APP: (Notion API JSON)[https://notioinapiassistant.streamlit.app]
11
+
12
+
13
+ class NotionHelper:
14
+ """A helper class to interact with the Notion API, providing methods for database and page management,
15
+ as well as file uploads and attachments.
16
+
17
+ This class simplifies interactions with the Notion API by wrapping common operations
18
+ such as creating, querying, and updating databases and pages. It also includes functionality
19
+ for handling file uploads and embedding them within Notion pages or attaching them to page properties.
20
+
21
+ Parameters
22
+ ----------
23
+ notion_token : str
24
+ The integration token for authenticating with the Notion API.
25
+
26
+ Methods
27
+ -------
28
+ get_database(database_id)
29
+ Retrieves the schema of a Notion database.
30
+ notion_search_db(database_id, query="")
31
+ Searches for pages in a database with a title containing the query.
32
+ notion_get_page(page_id)
33
+ Retrieves the properties and content blocks of a page.
34
+ create_database(parent_page_id, database_title, properties)
35
+ Creates a new database under a specified parent page.
36
+ new_page_to_db(database_id, page_properties)
37
+ Adds a new page to a database.
38
+ append_page_body(page_id, blocks)
39
+ Appends content blocks to a page.
40
+ get_all_page_ids(database_id)
41
+ Retrieves all page IDs from a database.
42
+ get_all_pages_as_json(database_id, limit=None)
43
+ Fetches all pages from a database as a list of JSON objects.
44
+ get_all_pages_as_dataframe(database_id, limit=None, include_page_ids=True)
45
+ Retrieves all pages from a database as a Pandas DataFrame.
46
+ upload_file(file_path)
47
+ Uploads a file to Notion's temporary storage.
48
+ attach_file_to_page(page_id, file_upload_id)
49
+ Attaches a previously uploaded file to a page body.
50
+ embed_image_to_page(page_id, file_upload_id)
51
+ Embeds a previously uploaded image into a page body.
52
+ attach_file_to_page_property(page_id, property_name, file_upload_id, file_name)
53
+ Attaches a previously uploaded file to a 'Files & Media' property of a page.
54
+ one_step_image_embed(page_id, file_path)
55
+ Uploads and embeds an image in a page in a single call.
56
+ one_step_file_to_page(page_id, file_path)
57
+ Uploads and attaches a file to a page body in a single call.
58
+ one_step_file_to_page_property(page_id, property_name, file_path, file_name)
59
+ Uploads and attaches a file to a page property in a single call.
60
+ """
61
+
62
+ def __init__(self, notion_token):
63
+ """Initializes the NotionHelper instance and authenticates with the Notion API
64
+ using the provided token."""
65
+ self.notion_token = notion_token
66
+ self.notion = AsyncClient(auth=self.notion_token)
67
+
68
+ async def get_database(self, database_id):
69
+ """Retrieves the schema of a Notion database given its database_id.
70
+
71
+ Parameters
72
+ ----------
73
+ database_id : str
74
+ The unique identifier of the Notion database.
75
+
76
+ Returns
77
+ -------
78
+ dict
79
+ A dictionary representing the database schema.
80
+ """
81
+ response = await self.notion.databases.retrieve(database_id=database_id)
82
+ return response
83
+
84
+ async def notion_search_db(
85
+ self, database_id="e18e2d110f9e401eb1adf3190e51a21b", query=""
86
+ ):
87
+ """Searches for pages in a Notion database that contain the specified query in their title."""
88
+ my_pages = await self.notion.databases.query(
89
+ database_id=database_id,
90
+ filter={
91
+ "property": "title",
92
+ "rich_text": {"contains": query},
93
+ },
94
+ )
95
+
96
+ page_title = my_pages["results"][0]["properties"]["Code / Notebook Description"]["title"][0]["plain_text"]
97
+ page_url = my_pages["results"][0]["url"]
98
+
99
+ page_list = my_pages["results"]
100
+ count = 1
101
+ for page in page_list:
102
+ try:
103
+ print(
104
+ count,
105
+ page["properties"]["Code / Notebook Description"]["title"][0]["plain_text"],
106
+ )
107
+ except IndexError:
108
+ print("No results found.")
109
+
110
+ print(page["url"])
111
+ print()
112
+ count += 1
113
+
114
+ # pprint.pprint(page)
115
+
116
+ async def notion_get_page(self, page_id):
117
+ """Retrieves the JSON of the page properties and an array of blocks on a Notion page given its page_id."""
118
+
119
+ # Retrieve the page and block data
120
+ page = await self.notion.pages.retrieve(page_id)
121
+ blocks = await self.notion.blocks.children.list(page_id)
122
+
123
+ # Extract all properties as a JSON object
124
+ properties = page.get("properties", {})
125
+ content = [block for block in blocks["results"]]
126
+
127
+ # Print the full JSON of the properties
128
+ print(properties)
129
+
130
+ # Return the properties JSON and blocks content
131
+ return {"properties": properties, "content": content}
132
+
133
+ async def create_database(self, parent_page_id, database_title, properties):
134
+ """Creates a new database in Notion.
135
+
136
+ This method creates a new database under a specified parent page with the provided title and property definitions.
137
+
138
+ Parameters:
139
+ parent_page_id (str): The unique identifier of the parent page.
140
+ database_title (str): The title for the new database.
141
+ properties (dict): A dictionary defining the property schema for the database.
142
+
143
+ Returns:
144
+ dict: The JSON response from the Notion API containing details about the created database.
145
+ """
146
+
147
+ # Define the properties for the database
148
+ new_database = {
149
+ "parent": {"type": "page_id", "page_id": parent_page_id},
150
+ "title": [{"type": "text", "text": {"content": database_title}}],
151
+ "properties": properties,
152
+ }
153
+
154
+ response = await self.notion.databases.create(**new_database)
155
+ return response
156
+
157
+ async def new_page_to_db(self, database_id, page_properties):
158
+ """Adds a new page to a Notion database."""
159
+
160
+ new_page = {
161
+ "parent": {"database_id": database_id},
162
+ "properties": page_properties,
163
+ }
164
+
165
+ response = await self.notion.pages.create(**new_page)
166
+ return response
167
+
168
+ async def append_page_body(self, page_id, blocks):
169
+ """Appends blocks of text to the body of a Notion page."""
170
+
171
+ new_blocks = {"children": blocks}
172
+
173
+ response = await self.notion.blocks.children.append(block_id=page_id, **new_blocks)
174
+ return response
175
+
176
+ async def get_all_page_ids(self, database_id):
177
+ """Returns the IDs of all pages in a given database."""
178
+
179
+ my_pages = await self.notion.databases.query(database_id=database_id)
180
+ page_ids = [page["id"] for page in my_pages["results"]]
181
+ return page_ids
182
+
183
+ async def get_all_pages_as_json(self, database_id, limit=None):
184
+ """Returns a list of JSON objects representing all pages in the given database, with all properties.
185
+ You can specify the number of entries to be loaded using the `limit` parameter.
186
+ """
187
+
188
+ # Use pagination to remove any limits on number of entries, optionally limited by `limit` argument
189
+ pages_json = []
190
+ has_more = True
191
+ start_cursor = None
192
+ count = 0
193
+
194
+ while has_more:
195
+ my_pages = await self.notion.databases.query(
196
+ **{
197
+ "database_id": database_id,
198
+ "start_cursor": start_cursor,
199
+ }
200
+ )
201
+ pages_json.extend([page["properties"] for page in my_pages["results"]])
202
+ has_more = my_pages.get("has_more", False)
203
+ start_cursor = my_pages.get("next_cursor", None)
204
+ count += len(my_pages["results"])
205
+
206
+ if limit is not None and count >= limit:
207
+ pages_json = pages_json[:limit]
208
+ break
209
+
210
+ return pages_json
211
+
212
+ async def get_all_pages_as_dataframe(self, database_id, limit=None, include_page_ids=True):
213
+ """Retrieves all pages from a Notion database and returns them as a Pandas DataFrame.
214
+
215
+ This method collects pages from the specified Notion database, optionally including the page IDs,
216
+ and extracts a predefined set of allowed properties from each page to form a structured DataFrame.
217
+ Numeric values are formatted to avoid scientific notation.
218
+
219
+ Parameters:
220
+ database_id (str): The identifier of the Notion database.
221
+ limit (int, optional): Maximum number of page entries to include. If None, all pages are retrieved.
222
+ include_page_ids (bool, optional): If True, includes an additional column 'notion_page_id' in the DataFrame.
223
+ Defaults to True.
224
+
225
+ Returns:
226
+ pandas.DataFrame: A DataFrame where each row represents a page with columns corresponding to page properties.
227
+ If include_page_ids is True, an additional column 'notion_page_id' is included.
228
+ """
229
+ # Retrieve pages with or without page IDs based on the flag
230
+ if include_page_ids:
231
+ pages_json = []
232
+ has_more = True
233
+ start_cursor = None
234
+ count = 0
235
+ # Retrieve pages with pagination including the page ID in properties
236
+ while has_more:
237
+ my_pages = await self.notion.databases.query(
238
+ database_id=database_id,
239
+ start_cursor=start_cursor,
240
+ )
241
+ for page in my_pages["results"]:
242
+ props = page["properties"]
243
+ props["notion_page_id"] = page.get("id", "")
244
+ pages_json.append(props)
245
+ has_more = my_pages.get("has_more", False)
246
+ start_cursor = my_pages.get("next_cursor", None)
247
+ count += len(my_pages["results"])
248
+ if limit is not None and count >= limit:
249
+ pages_json = pages_json[:limit]
250
+ break
251
+ else:
252
+ pages_json = await self.get_all_pages_as_json(database_id, limit=limit)
253
+
254
+ data = []
255
+ # Define the list of allowed property types that we want to extract
256
+ allowed_properties = [
257
+ "title",
258
+ "status",
259
+ "number",
260
+ "date",
261
+ "url",
262
+ "checkbox",
263
+ "rich_text",
264
+ "email",
265
+ "select",
266
+ "people",
267
+ "phone_number",
268
+ "multi_select",
269
+ "created_time",
270
+ "created_by",
271
+ "rollup",
272
+ "relation",
273
+ "last_edited_by",
274
+ "last_edited_time",
275
+ "formula",
276
+ "file",
277
+ ]
278
+ if include_page_ids:
279
+ allowed_properties.append("notion_page_id")
280
+
281
+ for page in pages_json:
282
+ row = {}
283
+ for key, value in page.items():
284
+ if key == "notion_page_id":
285
+ row[key] = value
286
+ continue
287
+ property_type = value.get("type", "")
288
+ if property_type in allowed_properties:
289
+ if property_type == "title":
290
+ row[key] = value.get("title", [{}])[0].get("plain_text", "")
291
+ elif property_type == "status":
292
+ row[key] = value.get("status", {}).get("name", "")
293
+ elif property_type == "number":
294
+ number_value = value.get("number", None)
295
+ row[key] = float(number_value) if isinstance(number_value, (int, float)) else None
296
+ elif property_type == "date":
297
+ date_field = value.get("date", {})
298
+ row[key] = date_field.get("start", "") if date_field else ""
299
+ elif property_type == "url":
300
+ row[key] = value.get("url", "")
301
+ elif property_type == "checkbox":
302
+ row[key] = value.get("checkbox", False)
303
+ elif property_type == "rich_text":
304
+ rich_text_field = value.get("rich_text", [])
305
+ row[key] = rich_text_field[0].get("plain_text", "") if rich_text_field else ""
306
+ elif property_type == "email":
307
+ row[key] = value.get("email", "")
308
+ elif property_type == "select":
309
+ select_field = value.get("select", {})
310
+ row[key] = select_field.get("name", "") if select_field else ""
311
+ elif property_type == "people":
312
+ people_list = value.get("people", [])
313
+ if people_list:
314
+ person = people_list[0]
315
+ row[key] = {"name": person.get("name", ""), "email": person.get("person", {}).get("email", "")}
316
+ elif property_type == "phone_number":
317
+ row[key] = value.get("phone_number", "")
318
+ elif property_type == "multi_select":
319
+ multi_select_field = value.get("multi_select", [])
320
+ row[key] = [item.get("name", "") for item in multi_select_field]
321
+ elif property_type == "created_time":
322
+ row[key] = value.get("created_time", "")
323
+ elif property_type == "created_by":
324
+ created_by = value.get("created_by", {})
325
+ row[key] = created_by.get("name", "")
326
+ elif property_type == "rollup":
327
+ rollup_field = value.get("rollup", {}).get("array", [])
328
+ row[key] = [item.get("date", {}).get("start", "") for item in rollup_field]
329
+ elif property_type == "relation":
330
+ relation_list = value.get("relation", [])
331
+ row[key] = [relation.get("id", "") for relation in relation_list]
332
+ elif property_type == "last_edited_by":
333
+ last_edited_by = value.get("last_edited_by", {})
334
+ row[key] = last_edited_by.get("name", "")
335
+ elif property_type == "last_edited_time":
336
+ row[key] = value.get("last_edited_time", "")
337
+ elif property_type == "formula":
338
+ formula_value = value.get("formula", {})
339
+ row[key] = formula_value.get(formula_value.get("type", ""), "")
340
+ elif property_type == "file":
341
+ files = value.get("files", [])
342
+ row[key] = [file.get("name", "") for file in files]
343
+ data.append(row)
344
+
345
+ df = pd.DataFrame(data)
346
+ pd.options.display.float_format = "{:.3f}".format
347
+ return df
348
+
349
+ async def upload_file(self, file_path):
350
+ """Uploads a file to Notion and returns the file upload object."""
351
+ async with httpx.AsyncClient() as client:
352
+ # Step 1: Create a File Upload object
353
+ create_upload_url = "https://api.notion.com/v1/file_uploads"
354
+ headers = {
355
+ "Authorization": f"Bearer {self.notion_token}",
356
+ "Content-Type": "application/json",
357
+ "Notion-Version": "2022-06-28",
358
+ }
359
+ response = await client.post(create_upload_url, headers=headers, json={})
360
+ upload_data = response.json()
361
+ upload_url = upload_data["upload_url"]
362
+
363
+ # Step 2: Upload file contents
364
+ with open(file_path, "rb") as f:
365
+ upload_headers = {
366
+ "Authorization": f"Bearer {self.notion_token}",
367
+ "Notion-Version": "2022-06-28",
368
+ }
369
+ files = {'file': (os.path.basename(file_path), f, mimetypes.guess_type(file_path)[0] or 'application/octet-stream')}
370
+ upload_response = await client.post(upload_url, headers=upload_headers, files=files)
371
+
372
+ return upload_response.json()
373
+
374
+ async def attach_file_to_page(self, page_id, file_upload_id):
375
+ """Attaches an uploaded file to a specific page."""
376
+ attach_url = f"https://api.notion.com/v1/blocks/{page_id}/children"
377
+ headers = {
378
+ "Authorization": f"Bearer {self.notion_token}",
379
+ "Content-Type": "application/json",
380
+ "Notion-Version": "2022-06-28",
381
+ }
382
+ data = {
383
+ "children": [
384
+ {
385
+ "type": "file",
386
+ "file": {
387
+ "type": "file_upload",
388
+ "file_upload": {
389
+ "id": file_upload_id
390
+ }
391
+ }
392
+ }
393
+ ]
394
+ }
395
+ async with httpx.AsyncClient() as client:
396
+ response = await client.patch(attach_url, headers=headers, json=data)
397
+ return response.json()
398
+
399
+ async def embed_image_to_page(self, page_id, file_upload_id):
400
+ """Embeds an uploaded image to a specific page."""
401
+ attach_url = f"https://api.notion.com/v1/blocks/{page_id}/children"
402
+ headers = {
403
+ "Authorization": f"Bearer {self.notion_token}",
404
+ "Content-Type": "application/json",
405
+ "Notion-Version": "2022-06-28",
406
+ }
407
+ data = {
408
+ "children": [
409
+ {
410
+ "type": "image",
411
+ "image": {
412
+ "type": "file_upload",
413
+ "file_upload": {
414
+ "id": file_upload_id
415
+ }
416
+ }
417
+ }
418
+ ]
419
+ }
420
+ async with httpx.AsyncClient() as client:
421
+ response = await client.patch(attach_url, headers=headers, json=data)
422
+ return response.json()
423
+
424
+ async def attach_file_to_page_property(
425
+ self, page_id, property_name, file_upload_id, file_name
426
+ ):
427
+ """Attaches a file to a Files & Media property on a specific page."""
428
+ update_url = f"https://api.notion.com/v1/pages/{page_id}"
429
+ headers = {
430
+ "Authorization": f"Bearer {self.notion_token}",
431
+ "Content-Type": "application/json",
432
+ "Notion-Version": "2022-06-28",
433
+ }
434
+ data = {
435
+ "properties": {
436
+ property_name: {
437
+ "files": [
438
+ {
439
+ "type": "file_upload",
440
+ "file_upload": {"id": file_upload_id},
441
+ "name": file_name,
442
+ }
443
+ ]
444
+ }
445
+ }
446
+ }
447
+ async with httpx.AsyncClient() as client:
448
+ response = await client.patch(update_url, headers=headers, json=data)
449
+ return response.json()
450
+
451
+ async def one_step_image_embed(self, page_id, file_path):
452
+ """Uploads an image and embeds it in a Notion page in one step."""
453
+
454
+ # Upload the file
455
+ file_upload = await self.upload_file(file_path)
456
+ file_upload_id = file_upload["id"]
457
+
458
+ # Embed the image in the page
459
+ return await self.embed_image_to_page(page_id, file_upload_id)
460
+
461
+ async def one_step_file_to_page(self, page_id, file_path):
462
+ """Uploads a file and attaches it to a Notion page in one step."""
463
+
464
+ # Upload the file
465
+ file_upload = await self.upload_file(file_path)
466
+ file_upload_id = file_upload["id"]
467
+
468
+ # Attach the file to the page
469
+ return await self.attach_file_to_page(page_id, file_upload_id)
470
+
471
+ async def one_step_file_to_page_property(self, page_id, property_name, file_path, file_name):
472
+ """Uploads a file and attaches it to a Notion page property in one step."""
473
+
474
+ # Upload the file
475
+ file_upload = await self.upload_file(file_path)
476
+ file_upload_id = file_upload["id"]
477
+
478
+ # Attach the file to the page property
479
+ return await self.attach_file_to_page_property(page_id, property_name, file_upload_id, file_name)
File without changes
@@ -0,0 +1,278 @@
1
+ version = 1
2
+ revision = 2
3
+ requires-python = ">=3.12"
4
+
5
+ [[package]]
6
+ name = "anyio"
7
+ version = "4.9.0"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ dependencies = [
10
+ { name = "idna" },
11
+ { name = "sniffio" },
12
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
13
+ ]
14
+ sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" }
15
+ wheels = [
16
+ { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" },
17
+ ]
18
+
19
+ [[package]]
20
+ name = "cassidy"
21
+ version = "0.1.4"
22
+ source = { registry = "https://pypi.org/simple" }
23
+ sdist = { url = "https://files.pythonhosted.org/packages/18/d0/4fa91fdcbfdbc05062023be347a6fb08c8e13433d8db7658c1e9b8cb49bb/cassidy-0.1.4.tar.gz", hash = "sha256:d51a0f4210a614f6b092e25fe29c981de0d9b769c42129b43708e8f847e22bee", size = 4325, upload-time = "2021-10-29T15:14:49.963Z" }
24
+ wheels = [
25
+ { url = "https://files.pythonhosted.org/packages/d0/92/c29e704ce0f9c37ccb20338d1ae00e7b31a064779c3a83a67ddd3375833c/cassidy-0.1.4-py3-none-any.whl", hash = "sha256:9e6fdfff81accd7766f9b3e6665a1c0a914fd7b23c6da16d9face886bc1fb7d8", size = 6219, upload-time = "2021-10-29T15:14:48.684Z" },
26
+ ]
27
+
28
+ [[package]]
29
+ name = "certifi"
30
+ version = "2025.7.14"
31
+ source = { registry = "https://pypi.org/simple" }
32
+ sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" }
33
+ wheels = [
34
+ { url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" },
35
+ ]
36
+
37
+ [[package]]
38
+ name = "enumb"
39
+ version = "0.1.5"
40
+ source = { registry = "https://pypi.org/simple" }
41
+ dependencies = [
42
+ { name = "cassidy" },
43
+ { name = "expo" },
44
+ ]
45
+ sdist = { url = "https://files.pythonhosted.org/packages/4d/dd/f19ba71555f477165d44fc5e9403b398ca374504ac9db2ed7e2fec8268b4/enumb-0.1.5.tar.gz", hash = "sha256:02a6eda94322ae06a52754e46be6d89310b21e0751a9fc5c9546e977b4fa1884", size = 3165, upload-time = "2021-11-10T20:57:17.057Z" }
46
+ wheels = [
47
+ { url = "https://files.pythonhosted.org/packages/e5/79/28cbc2ff3ef8ed3c0a3c2ad797de40e227735abc6a1fe57782b7531e8bfb/enumb-0.1.5-py3-none-any.whl", hash = "sha256:1fd798bc347eecb598de9f95bc71cedd96baea3d4ad95601bfc9e18700b1e097", size = 4611, upload-time = "2021-11-10T20:57:15.443Z" },
48
+ ]
49
+
50
+ [[package]]
51
+ name = "expo"
52
+ version = "0.1.2"
53
+ source = { registry = "https://pypi.org/simple" }
54
+ sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/6a0b80dc50de4b02406a06e5bab80a881e2275e7f247f133fb2da904ce2b/expo-0.1.2.tar.gz", hash = "sha256:df9042d9d73307bf987e89791b6e36744c5fa99f7464210e956e76d7fe3e84bd", size = 1901, upload-time = "2021-10-29T15:15:23.557Z" }
55
+ wheels = [
56
+ { url = "https://files.pythonhosted.org/packages/0a/f6/1ce363356dc85bb970c153df35ad2bb49468bc119c4896ca106731373e2e/expo-0.1.2-py3-none-any.whl", hash = "sha256:a36d64c6954de353ee67491351362b04c1b3281acb69afa8534b41279ecd2306", size = 2472, upload-time = "2021-10-29T15:15:22.283Z" },
57
+ ]
58
+
59
+ [[package]]
60
+ name = "h11"
61
+ version = "0.16.0"
62
+ source = { registry = "https://pypi.org/simple" }
63
+ sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
64
+ wheels = [
65
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
66
+ ]
67
+
68
+ [[package]]
69
+ name = "httpcore"
70
+ version = "1.0.9"
71
+ source = { registry = "https://pypi.org/simple" }
72
+ dependencies = [
73
+ { name = "certifi" },
74
+ { name = "h11" },
75
+ ]
76
+ sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
77
+ wheels = [
78
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
79
+ ]
80
+
81
+ [[package]]
82
+ name = "httpx"
83
+ version = "0.28.1"
84
+ source = { registry = "https://pypi.org/simple" }
85
+ dependencies = [
86
+ { name = "anyio" },
87
+ { name = "certifi" },
88
+ { name = "httpcore" },
89
+ { name = "idna" },
90
+ ]
91
+ sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
92
+ wheels = [
93
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
94
+ ]
95
+
96
+ [[package]]
97
+ name = "idna"
98
+ version = "3.10"
99
+ source = { registry = "https://pypi.org/simple" }
100
+ sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
101
+ wheels = [
102
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
103
+ ]
104
+
105
+ [[package]]
106
+ name = "mimetype"
107
+ version = "0.1.5"
108
+ source = { registry = "https://pypi.org/simple" }
109
+ dependencies = [
110
+ { name = "enumb" },
111
+ ]
112
+ sdist = { url = "https://files.pythonhosted.org/packages/59/0c/184d0bc85babf00534d5c8adbf008dd5e0f79b7b43f8962e3cca2d90721c/mimetype-0.1.5.tar.gz", hash = "sha256:0ccae479eb36d3ff0553480e9df7738f2789529e5388560ad364ca06eecaa297", size = 28519, upload-time = "2021-10-29T18:33:15.205Z" }
113
+ wheels = [
114
+ { url = "https://files.pythonhosted.org/packages/a1/c7/96f2728f13e996fb311a8f940ef7693ae5eb131c37f66a4b7992ff8f7340/mimetype-0.1.5-py3-none-any.whl", hash = "sha256:e59720b6249761acef63b0eca246d3ae43a8d3a04f1964136a02d8a8c08d8cbb", size = 29752, upload-time = "2021-10-29T18:33:13.372Z" },
115
+ ]
116
+
117
+ [[package]]
118
+ name = "notion-client"
119
+ version = "2.4.0"
120
+ source = { registry = "https://pypi.org/simple" }
121
+ dependencies = [
122
+ { name = "httpx" },
123
+ ]
124
+ sdist = { url = "https://files.pythonhosted.org/packages/6d/49/d6a8ac78256113ff70aa24e2e1c1f5efc86034ad6a2e6415f1d56a3035aa/notion_client-2.4.0.tar.gz", hash = "sha256:e7ff32f733fdbe0f18a37f5d98ff665681e5b3c4dcf2faa6e602bb1b16a3b15d", size = 18655, upload-time = "2025-06-17T10:59:20.868Z" }
125
+ wheels = [
126
+ { url = "https://files.pythonhosted.org/packages/84/3c/27fa2772e0c6b64e732ba7549559d0eaf90808508a091474568f23d72900/notion_client-2.4.0-py2.py3-none-any.whl", hash = "sha256:89f47c0a5eedc08f1170c04e85f422091ce3e095f20b69a3877152e875f0094f", size = 13835, upload-time = "2025-06-17T10:59:19.993Z" },
127
+ ]
128
+
129
+ [[package]]
130
+ name = "notionhelper"
131
+ version = "0.1.0"
132
+ source = { editable = "." }
133
+ dependencies = [
134
+ { name = "httpx" },
135
+ { name = "mimetype" },
136
+ { name = "notion-client" },
137
+ { name = "pandas" },
138
+ ]
139
+
140
+ [package.metadata]
141
+ requires-dist = [
142
+ { name = "httpx", specifier = ">=0.27.0" },
143
+ { name = "mimetype", specifier = ">=0.1.5" },
144
+ { name = "notion-client", specifier = ">=2.4.0" },
145
+ { name = "pandas", specifier = ">=2.3.1" },
146
+ ]
147
+
148
+ [[package]]
149
+ name = "numpy"
150
+ version = "2.3.1"
151
+ source = { registry = "https://pypi.org/simple" }
152
+ sdist = { url = "https://files.pythonhosted.org/packages/2e/19/d7c972dfe90a353dbd3efbbe1d14a5951de80c99c9dc1b93cd998d51dc0f/numpy-2.3.1.tar.gz", hash = "sha256:1ec9ae20a4226da374362cca3c62cd753faf2f951440b0e3b98e93c235441d2b", size = 20390372, upload-time = "2025-06-21T12:28:33.469Z" }
153
+ wheels = [
154
+ { url = "https://files.pythonhosted.org/packages/c6/56/71ad5022e2f63cfe0ca93559403d0edef14aea70a841d640bd13cdba578e/numpy-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2959d8f268f3d8ee402b04a9ec4bb7604555aeacf78b360dc4ec27f1d508177d", size = 20896664, upload-time = "2025-06-21T12:15:30.845Z" },
155
+ { url = "https://files.pythonhosted.org/packages/25/65/2db52ba049813670f7f987cc5db6dac9be7cd95e923cc6832b3d32d87cef/numpy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:762e0c0c6b56bdedfef9a8e1d4538556438288c4276901ea008ae44091954e29", size = 14131078, upload-time = "2025-06-21T12:15:52.23Z" },
156
+ { url = "https://files.pythonhosted.org/packages/57/dd/28fa3c17b0e751047ac928c1e1b6990238faad76e9b147e585b573d9d1bd/numpy-2.3.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:867ef172a0976aaa1f1d1b63cf2090de8b636a7674607d514505fb7276ab08fc", size = 5112554, upload-time = "2025-06-21T12:16:01.434Z" },
157
+ { url = "https://files.pythonhosted.org/packages/c9/fc/84ea0cba8e760c4644b708b6819d91784c290288c27aca916115e3311d17/numpy-2.3.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4e602e1b8682c2b833af89ba641ad4176053aaa50f5cacda1a27004352dde943", size = 6646560, upload-time = "2025-06-21T12:16:11.895Z" },
158
+ { url = "https://files.pythonhosted.org/packages/61/b2/512b0c2ddec985ad1e496b0bd853eeb572315c0f07cd6997473ced8f15e2/numpy-2.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8e333040d069eba1652fb08962ec5b76af7f2c7bce1df7e1418c8055cf776f25", size = 14260638, upload-time = "2025-06-21T12:16:32.611Z" },
159
+ { url = "https://files.pythonhosted.org/packages/6e/45/c51cb248e679a6c6ab14b7a8e3ead3f4a3fe7425fc7a6f98b3f147bec532/numpy-2.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e7cbf5a5eafd8d230a3ce356d892512185230e4781a361229bd902ff403bc660", size = 16632729, upload-time = "2025-06-21T12:16:57.439Z" },
160
+ { url = "https://files.pythonhosted.org/packages/e4/ff/feb4be2e5c09a3da161b412019caf47183099cbea1132fd98061808c2df2/numpy-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1b8f26d1086835f442286c1d9b64bb3974b0b1e41bb105358fd07d20872952", size = 15565330, upload-time = "2025-06-21T12:17:20.638Z" },
161
+ { url = "https://files.pythonhosted.org/packages/bc/6d/ceafe87587101e9ab0d370e4f6e5f3f3a85b9a697f2318738e5e7e176ce3/numpy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee8340cb48c9b7a5899d1149eece41ca535513a9698098edbade2a8e7a84da77", size = 18361734, upload-time = "2025-06-21T12:17:47.938Z" },
162
+ { url = "https://files.pythonhosted.org/packages/2b/19/0fb49a3ea088be691f040c9bf1817e4669a339d6e98579f91859b902c636/numpy-2.3.1-cp312-cp312-win32.whl", hash = "sha256:e772dda20a6002ef7061713dc1e2585bc1b534e7909b2030b5a46dae8ff077ab", size = 6320411, upload-time = "2025-06-21T12:17:58.475Z" },
163
+ { url = "https://files.pythonhosted.org/packages/b1/3e/e28f4c1dd9e042eb57a3eb652f200225e311b608632bc727ae378623d4f8/numpy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfecc7822543abdea6de08758091da655ea2210b8ffa1faf116b940693d3df76", size = 12734973, upload-time = "2025-06-21T12:18:17.601Z" },
164
+ { url = "https://files.pythonhosted.org/packages/04/a8/8a5e9079dc722acf53522b8f8842e79541ea81835e9b5483388701421073/numpy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:7be91b2239af2658653c5bb6f1b8bccafaf08226a258caf78ce44710a0160d30", size = 10191491, upload-time = "2025-06-21T12:18:33.585Z" },
165
+ { url = "https://files.pythonhosted.org/packages/d4/bd/35ad97006d8abff8631293f8ea6adf07b0108ce6fec68da3c3fcca1197f2/numpy-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25a1992b0a3fdcdaec9f552ef10d8103186f5397ab45e2d25f8ac51b1a6b97e8", size = 20889381, upload-time = "2025-06-21T12:19:04.103Z" },
166
+ { url = "https://files.pythonhosted.org/packages/f1/4f/df5923874d8095b6062495b39729178eef4a922119cee32a12ee1bd4664c/numpy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dea630156d39b02a63c18f508f85010230409db5b2927ba59c8ba4ab3e8272e", size = 14152726, upload-time = "2025-06-21T12:19:25.599Z" },
167
+ { url = "https://files.pythonhosted.org/packages/8c/0f/a1f269b125806212a876f7efb049b06c6f8772cf0121139f97774cd95626/numpy-2.3.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bada6058dd886061f10ea15f230ccf7dfff40572e99fef440a4a857c8728c9c0", size = 5105145, upload-time = "2025-06-21T12:19:34.782Z" },
168
+ { url = "https://files.pythonhosted.org/packages/6d/63/a7f7fd5f375b0361682f6ffbf686787e82b7bbd561268e4f30afad2bb3c0/numpy-2.3.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:a894f3816eb17b29e4783e5873f92faf55b710c2519e5c351767c51f79d8526d", size = 6639409, upload-time = "2025-06-21T12:19:45.228Z" },
169
+ { url = "https://files.pythonhosted.org/packages/bf/0d/1854a4121af895aab383f4aa233748f1df4671ef331d898e32426756a8a6/numpy-2.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:18703df6c4a4fee55fd3d6e5a253d01c5d33a295409b03fda0c86b3ca2ff41a1", size = 14257630, upload-time = "2025-06-21T12:20:06.544Z" },
170
+ { url = "https://files.pythonhosted.org/packages/50/30/af1b277b443f2fb08acf1c55ce9d68ee540043f158630d62cef012750f9f/numpy-2.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5902660491bd7a48b2ec16c23ccb9124b8abfd9583c5fdfa123fe6b421e03de1", size = 16627546, upload-time = "2025-06-21T12:20:31.002Z" },
171
+ { url = "https://files.pythonhosted.org/packages/6e/ec/3b68220c277e463095342d254c61be8144c31208db18d3fd8ef02712bcd6/numpy-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36890eb9e9d2081137bd78d29050ba63b8dab95dff7912eadf1185e80074b2a0", size = 15562538, upload-time = "2025-06-21T12:20:54.322Z" },
172
+ { url = "https://files.pythonhosted.org/packages/77/2b/4014f2bcc4404484021c74d4c5ee8eb3de7e3f7ac75f06672f8dcf85140a/numpy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a780033466159c2270531e2b8ac063704592a0bc62ec4a1b991c7c40705eb0e8", size = 18360327, upload-time = "2025-06-21T12:21:21.053Z" },
173
+ { url = "https://files.pythonhosted.org/packages/40/8d/2ddd6c9b30fcf920837b8672f6c65590c7d92e43084c25fc65edc22e93ca/numpy-2.3.1-cp313-cp313-win32.whl", hash = "sha256:39bff12c076812595c3a306f22bfe49919c5513aa1e0e70fac756a0be7c2a2b8", size = 6312330, upload-time = "2025-06-21T12:25:07.447Z" },
174
+ { url = "https://files.pythonhosted.org/packages/dd/c8/beaba449925988d415efccb45bf977ff8327a02f655090627318f6398c7b/numpy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d5ee6eec45f08ce507a6570e06f2f879b374a552087a4179ea7838edbcbfa42", size = 12731565, upload-time = "2025-06-21T12:25:26.444Z" },
175
+ { url = "https://files.pythonhosted.org/packages/0b/c3/5c0c575d7ec78c1126998071f58facfc124006635da75b090805e642c62e/numpy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c4d9e0a8368db90f93bd192bfa771ace63137c3488d198ee21dfb8e7771916e", size = 10190262, upload-time = "2025-06-21T12:25:42.196Z" },
176
+ { url = "https://files.pythonhosted.org/packages/ea/19/a029cd335cf72f79d2644dcfc22d90f09caa86265cbbde3b5702ccef6890/numpy-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b0b5397374f32ec0649dd98c652a1798192042e715df918c20672c62fb52d4b8", size = 20987593, upload-time = "2025-06-21T12:21:51.664Z" },
177
+ { url = "https://files.pythonhosted.org/packages/25/91/8ea8894406209107d9ce19b66314194675d31761fe2cb3c84fe2eeae2f37/numpy-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c5bdf2015ccfcee8253fb8be695516ac4457c743473a43290fd36eba6a1777eb", size = 14300523, upload-time = "2025-06-21T12:22:13.583Z" },
178
+ { url = "https://files.pythonhosted.org/packages/a6/7f/06187b0066eefc9e7ce77d5f2ddb4e314a55220ad62dd0bfc9f2c44bac14/numpy-2.3.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d70f20df7f08b90a2062c1f07737dd340adccf2068d0f1b9b3d56e2038979fee", size = 5227993, upload-time = "2025-06-21T12:22:22.53Z" },
179
+ { url = "https://files.pythonhosted.org/packages/e8/ec/a926c293c605fa75e9cfb09f1e4840098ed46d2edaa6e2152ee35dc01ed3/numpy-2.3.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:2fb86b7e58f9ac50e1e9dd1290154107e47d1eef23a0ae9145ded06ea606f992", size = 6736652, upload-time = "2025-06-21T12:22:33.629Z" },
180
+ { url = "https://files.pythonhosted.org/packages/e3/62/d68e52fb6fde5586650d4c0ce0b05ff3a48ad4df4ffd1b8866479d1d671d/numpy-2.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:23ab05b2d241f76cb883ce8b9a93a680752fbfcbd51c50eff0b88b979e471d8c", size = 14331561, upload-time = "2025-06-21T12:22:55.056Z" },
181
+ { url = "https://files.pythonhosted.org/packages/fc/ec/b74d3f2430960044bdad6900d9f5edc2dc0fb8bf5a0be0f65287bf2cbe27/numpy-2.3.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ce2ce9e5de4703a673e705183f64fd5da5bf36e7beddcb63a25ee2286e71ca48", size = 16693349, upload-time = "2025-06-21T12:23:20.53Z" },
182
+ { url = "https://files.pythonhosted.org/packages/0d/15/def96774b9d7eb198ddadfcbd20281b20ebb510580419197e225f5c55c3e/numpy-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c4913079974eeb5c16ccfd2b1f09354b8fed7e0d6f2cab933104a09a6419b1ee", size = 15642053, upload-time = "2025-06-21T12:23:43.697Z" },
183
+ { url = "https://files.pythonhosted.org/packages/2b/57/c3203974762a759540c6ae71d0ea2341c1fa41d84e4971a8e76d7141678a/numpy-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:010ce9b4f00d5c036053ca684c77441f2f2c934fd23bee058b4d6f196efd8280", size = 18434184, upload-time = "2025-06-21T12:24:10.708Z" },
184
+ { url = "https://files.pythonhosted.org/packages/22/8a/ccdf201457ed8ac6245187850aff4ca56a79edbea4829f4e9f14d46fa9a5/numpy-2.3.1-cp313-cp313t-win32.whl", hash = "sha256:6269b9edfe32912584ec496d91b00b6d34282ca1d07eb10e82dfc780907d6c2e", size = 6440678, upload-time = "2025-06-21T12:24:21.596Z" },
185
+ { url = "https://files.pythonhosted.org/packages/f1/7e/7f431d8bd8eb7e03d79294aed238b1b0b174b3148570d03a8a8a8f6a0da9/numpy-2.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2a809637460e88a113e186e87f228d74ae2852a2e0c44de275263376f17b5bdc", size = 12870697, upload-time = "2025-06-21T12:24:40.644Z" },
186
+ { url = "https://files.pythonhosted.org/packages/d4/ca/af82bf0fad4c3e573c6930ed743b5308492ff19917c7caaf2f9b6f9e2e98/numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244", size = 10260376, upload-time = "2025-06-21T12:24:56.884Z" },
187
+ ]
188
+
189
+ [[package]]
190
+ name = "pandas"
191
+ version = "2.3.1"
192
+ source = { registry = "https://pypi.org/simple" }
193
+ dependencies = [
194
+ { name = "numpy" },
195
+ { name = "python-dateutil" },
196
+ { name = "pytz" },
197
+ { name = "tzdata" },
198
+ ]
199
+ sdist = { url = "https://files.pythonhosted.org/packages/d1/6f/75aa71f8a14267117adeeed5d21b204770189c0a0025acbdc03c337b28fc/pandas-2.3.1.tar.gz", hash = "sha256:0a95b9ac964fe83ce317827f80304d37388ea77616b1425f0ae41c9d2d0d7bb2", size = 4487493, upload-time = "2025-07-07T19:20:04.079Z" }
200
+ wheels = [
201
+ { url = "https://files.pythonhosted.org/packages/46/de/b8445e0f5d217a99fe0eeb2f4988070908979bec3587c0633e5428ab596c/pandas-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:689968e841136f9e542020698ee1c4fbe9caa2ed2213ae2388dc7b81721510d3", size = 11588172, upload-time = "2025-07-07T19:18:52.054Z" },
202
+ { url = "https://files.pythonhosted.org/packages/1e/e0/801cdb3564e65a5ac041ab99ea6f1d802a6c325bb6e58c79c06a3f1cd010/pandas-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:025e92411c16cbe5bb2a4abc99732a6b132f439b8aab23a59fa593eb00704232", size = 10717365, upload-time = "2025-07-07T19:18:54.785Z" },
203
+ { url = "https://files.pythonhosted.org/packages/51/a5/c76a8311833c24ae61a376dbf360eb1b1c9247a5d9c1e8b356563b31b80c/pandas-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b7ff55f31c4fcb3e316e8f7fa194566b286d6ac430afec0d461163312c5841e", size = 11280411, upload-time = "2025-07-07T19:18:57.045Z" },
204
+ { url = "https://files.pythonhosted.org/packages/da/01/e383018feba0a1ead6cf5fe8728e5d767fee02f06a3d800e82c489e5daaf/pandas-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dcb79bf373a47d2a40cf7232928eb7540155abbc460925c2c96d2d30b006eb4", size = 11988013, upload-time = "2025-07-07T19:18:59.771Z" },
205
+ { url = "https://files.pythonhosted.org/packages/5b/14/cec7760d7c9507f11c97d64f29022e12a6cc4fc03ac694535e89f88ad2ec/pandas-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56a342b231e8862c96bdb6ab97170e203ce511f4d0429589c8ede1ee8ece48b8", size = 12767210, upload-time = "2025-07-07T19:19:02.944Z" },
206
+ { url = "https://files.pythonhosted.org/packages/50/b9/6e2d2c6728ed29fb3d4d4d302504fb66f1a543e37eb2e43f352a86365cdf/pandas-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca7ed14832bce68baef331f4d7f294411bed8efd032f8109d690df45e00c4679", size = 13440571, upload-time = "2025-07-07T19:19:06.82Z" },
207
+ { url = "https://files.pythonhosted.org/packages/80/a5/3a92893e7399a691bad7664d977cb5e7c81cf666c81f89ea76ba2bff483d/pandas-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ac942bfd0aca577bef61f2bc8da8147c4ef6879965ef883d8e8d5d2dc3e744b8", size = 10987601, upload-time = "2025-07-07T19:19:09.589Z" },
208
+ { url = "https://files.pythonhosted.org/packages/32/ed/ff0a67a2c5505e1854e6715586ac6693dd860fbf52ef9f81edee200266e7/pandas-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9026bd4a80108fac2239294a15ef9003c4ee191a0f64b90f170b40cfb7cf2d22", size = 11531393, upload-time = "2025-07-07T19:19:12.245Z" },
209
+ { url = "https://files.pythonhosted.org/packages/c7/db/d8f24a7cc9fb0972adab0cc80b6817e8bef888cfd0024eeb5a21c0bb5c4a/pandas-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6de8547d4fdb12421e2d047a2c446c623ff4c11f47fddb6b9169eb98ffba485a", size = 10668750, upload-time = "2025-07-07T19:19:14.612Z" },
210
+ { url = "https://files.pythonhosted.org/packages/0f/b0/80f6ec783313f1e2356b28b4fd8d2148c378370045da918c73145e6aab50/pandas-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:782647ddc63c83133b2506912cc6b108140a38a37292102aaa19c81c83db2928", size = 11342004, upload-time = "2025-07-07T19:19:16.857Z" },
211
+ { url = "https://files.pythonhosted.org/packages/e9/e2/20a317688435470872885e7fc8f95109ae9683dec7c50be29b56911515a5/pandas-2.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba6aff74075311fc88504b1db890187a3cd0f887a5b10f5525f8e2ef55bfdb9", size = 12050869, upload-time = "2025-07-07T19:19:19.265Z" },
212
+ { url = "https://files.pythonhosted.org/packages/55/79/20d746b0a96c67203a5bee5fb4e00ac49c3e8009a39e1f78de264ecc5729/pandas-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e5635178b387bd2ba4ac040f82bc2ef6e6b500483975c4ebacd34bec945fda12", size = 12750218, upload-time = "2025-07-07T19:19:21.547Z" },
213
+ { url = "https://files.pythonhosted.org/packages/7c/0f/145c8b41e48dbf03dd18fdd7f24f8ba95b8254a97a3379048378f33e7838/pandas-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f3bf5ec947526106399a9e1d26d40ee2b259c66422efdf4de63c848492d91bb", size = 13416763, upload-time = "2025-07-07T19:19:23.939Z" },
214
+ { url = "https://files.pythonhosted.org/packages/b2/c0/54415af59db5cdd86a3d3bf79863e8cc3fa9ed265f0745254061ac09d5f2/pandas-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956", size = 10987482, upload-time = "2025-07-07T19:19:42.699Z" },
215
+ { url = "https://files.pythonhosted.org/packages/48/64/2fd2e400073a1230e13b8cd604c9bc95d9e3b962e5d44088ead2e8f0cfec/pandas-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8dfc17328e8da77be3cf9f47509e5637ba8f137148ed0e9b5241e1baf526e20a", size = 12029159, upload-time = "2025-07-07T19:19:26.362Z" },
216
+ { url = "https://files.pythonhosted.org/packages/d8/0a/d84fd79b0293b7ef88c760d7dca69828d867c89b6d9bc52d6a27e4d87316/pandas-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ec6c851509364c59a5344458ab935e6451b31b818be467eb24b0fe89bd05b6b9", size = 11393287, upload-time = "2025-07-07T19:19:29.157Z" },
217
+ { url = "https://files.pythonhosted.org/packages/50/ae/ff885d2b6e88f3c7520bb74ba319268b42f05d7e583b5dded9837da2723f/pandas-2.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:911580460fc4884d9b05254b38a6bfadddfcc6aaef856fb5859e7ca202e45275", size = 11309381, upload-time = "2025-07-07T19:19:31.436Z" },
218
+ { url = "https://files.pythonhosted.org/packages/85/86/1fa345fc17caf5d7780d2699985c03dbe186c68fee00b526813939062bb0/pandas-2.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f4d6feeba91744872a600e6edbbd5b033005b431d5ae8379abee5bcfa479fab", size = 11883998, upload-time = "2025-07-07T19:19:34.267Z" },
219
+ { url = "https://files.pythonhosted.org/packages/81/aa/e58541a49b5e6310d89474333e994ee57fea97c8aaa8fc7f00b873059bbf/pandas-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fe37e757f462d31a9cd7580236a82f353f5713a80e059a29753cf938c6775d96", size = 12704705, upload-time = "2025-07-07T19:19:36.856Z" },
220
+ { url = "https://files.pythonhosted.org/packages/d5/f9/07086f5b0f2a19872554abeea7658200824f5835c58a106fa8f2ae96a46c/pandas-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5db9637dbc24b631ff3707269ae4559bce4b7fd75c1c4d7e13f40edc42df4444", size = 13189044, upload-time = "2025-07-07T19:19:39.999Z" },
221
+ ]
222
+
223
+ [[package]]
224
+ name = "python-dateutil"
225
+ version = "2.9.0.post0"
226
+ source = { registry = "https://pypi.org/simple" }
227
+ dependencies = [
228
+ { name = "six" },
229
+ ]
230
+ sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
231
+ wheels = [
232
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
233
+ ]
234
+
235
+ [[package]]
236
+ name = "pytz"
237
+ version = "2025.2"
238
+ source = { registry = "https://pypi.org/simple" }
239
+ sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
240
+ wheels = [
241
+ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
242
+ ]
243
+
244
+ [[package]]
245
+ name = "six"
246
+ version = "1.17.0"
247
+ source = { registry = "https://pypi.org/simple" }
248
+ sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
249
+ wheels = [
250
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
251
+ ]
252
+
253
+ [[package]]
254
+ name = "sniffio"
255
+ version = "1.3.1"
256
+ source = { registry = "https://pypi.org/simple" }
257
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
258
+ wheels = [
259
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
260
+ ]
261
+
262
+ [[package]]
263
+ name = "typing-extensions"
264
+ version = "4.14.1"
265
+ source = { registry = "https://pypi.org/simple" }
266
+ sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" }
267
+ wheels = [
268
+ { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" },
269
+ ]
270
+
271
+ [[package]]
272
+ name = "tzdata"
273
+ version = "2025.2"
274
+ source = { registry = "https://pypi.org/simple" }
275
+ sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
276
+ wheels = [
277
+ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
278
+ ]