Coverage for notion_client/helpers.py: 100%
66 statements
« prev ^ index » next coverage.py v7.6.0, created at 2024-07-13 22:22 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2024-07-13 22:22 +0000
1"""Utility functions for notion-sdk-py."""
2from typing import Any, AsyncGenerator, Awaitable, Callable, Dict, Generator, List
3from urllib.parse import urlparse
4from uuid import UUID
7def pick(base: Dict[Any, Any], *keys: str) -> Dict[Any, Any]:
8 """Return a dict composed of key value pairs for keys passed as args."""
9 result = {}
10 for key in keys:
11 if key not in base:
12 continue
13 value = base.get(key)
14 if value is None and key == "start_cursor":
15 continue
16 result[key] = value
17 return result
20def get_url(object_id: str) -> str:
21 """Return the URL for the object with the given id."""
22 return f"https://notion.so/{UUID(object_id).hex}"
25def get_id(url: str) -> str:
26 """Return the id of the object behind the given URL."""
27 parsed = urlparse(url)
28 if parsed.netloc not in ("notion.so", "www.notion.so"):
29 raise ValueError("Not a valid Notion URL.")
30 path = parsed.path
31 if len(path) < 32:
32 raise ValueError("The path in the URL seems to be incorrect.")
33 raw_id = path[-32:]
34 return str(UUID(raw_id))
37def iterate_paginated_api(
38 function: Callable[..., Any], **kwargs: Any
39) -> Generator[List[Any], None, None]:
40 """Return an iterator over the results of any paginated Notion API."""
41 next_cursor = kwargs.pop("start_cursor", None)
43 while True:
44 response = function(**kwargs, start_cursor=next_cursor)
45 for result in response.get("results"):
46 yield result
48 next_cursor = response.get("next_cursor")
49 if not response.get("has_more") or not next_cursor:
50 return
53def collect_paginated_api(function: Callable[..., Any], **kwargs: Any) -> List[Any]:
54 """Collect all the results of paginating an API into a list."""
55 return [result for result in iterate_paginated_api(function, **kwargs)]
58async def async_iterate_paginated_api(
59 function: Callable[..., Awaitable[Any]], **kwargs: Any
60) -> AsyncGenerator[List[Any], None]:
61 """Return an async iterator over the results of any paginated Notion API."""
62 next_cursor = kwargs.pop("start_cursor", None)
64 while True:
65 response = await function(**kwargs, start_cursor=next_cursor)
66 for result in response.get("results"):
67 yield result
69 next_cursor = response.get("next_cursor")
70 if (not response["has_more"]) | (next_cursor is None):
71 return
74async def async_collect_paginated_api(
75 function: Callable[..., Awaitable[Any]], **kwargs: Any
76) -> List[Any]:
77 """Collect asynchronously all the results of paginating an API into a list."""
78 return [result async for result in async_iterate_paginated_api(function, **kwargs)]
81def is_full_block(response: Dict[Any, Any]) -> bool:
82 """Return `True` if response is a full block."""
83 return response.get("object") == "block" and "type" in response
86def is_full_page(response: Dict[Any, Any]) -> bool:
87 """Return `True` if response is a full page."""
88 return response.get("object") == "page" and "url" in response
91def is_full_database(response: Dict[Any, Any]) -> bool:
92 """Return `True` if response is a full database."""
93 return response.get("object") == "database" and "title" in response
96def is_full_page_or_database(response: Dict[Any, Any]) -> bool:
97 """Return `True` if `response` is a full database or a full page."""
98 if response.get("object") == "database":
99 return is_full_database(response)
100 return is_full_page(response)
103def is_full_user(response: Dict[Any, Any]) -> bool:
104 """Return `True` if response is a full user."""
105 return "type" in response
108def is_full_comment(response: Dict[Any, Any]) -> bool:
109 """Return `True` if response is a full comment."""
110 return "type" in response
113def is_text_rich_text_item_response(rich_text: Dict[Any, Any]) -> bool:
114 """Return `True` if `rich_text` is a text."""
115 return rich_text.get("type") == "text"
118def is_equation_rich_text_item_response(rich_text: Dict[Any, Any]) -> bool:
119 """Return `True` if `rich_text` is an equation."""
120 return rich_text.get("type") == "equation"
123def is_mention_rich_text_item_response(rich_text: Dict[Any, Any]) -> bool:
124 """Return `True` if `rich_text` is a mention."""
125 return rich_text.get("type") == "mention"