<!-- markdownlint-disable -->
![notion-sdk-py](https://socialify.git.ci/ramnes/notion-sdk-py/image?font=Bitter&language=1&logo=https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2F4%2F45%2FNotion_app_logo.png&owner=1&pattern=Circuit%20Board&theme=Light)
<div align="center">
<p>
<a href="https://pypi.org/project/notion-client"><img src="https://img.shields.io/pypi/v/notion-client.svg" alt="PyPI"></a>
<a href="tox.ini"><img src="https://img.shields.io/pypi/pyversions/notion-client" alt="Supported Python Versions"></a>
<br/>
<a href="LICENSE"><img src="https://img.shields.io/github/license/ramnes/notion-sdk-py" alt="License"></a>
<a href="https://github.com/ambv/black"><img src="https://img.shields.io/badge/code%20style-black-black" alt="Code style"></a>
<a href="https://codecov.io/github/ramnes/notion-sdk-py"><img src="https://codecov.io/gh/ramnes/notion-sdk-py/branch/main/graphs/badge.svg" alt="Coverage"></a>
<a href="https://snyk.io/advisor/python/notion-client"><img src="https://snyk.io/advisor/python/notion-client/badge.svg" alt="Package health"></a>
<br/>
<a href="https://github.com/ramnes/notion-sdk-py/actions/workflows/quality.yml"><img src="https://github.com/ramnes/notion-sdk-py/actions/workflows/quality.yml/badge.svg" alt="Code Quality"></a>
<a href="https://github.com/ramnes/notion-sdk-py/actions/workflows/test.yml"><img src="https://github.com/ramnes/notion-sdk-py/actions/workflows/test.yml/badge.svg" alt="Tests"></a>
<a href="https://github.com/ramnes/notion-sdk-py/actions/workflows/docs.yml"><img src="https://github.com/ramnes/notion-sdk-py/actions/workflows/docs.yml/badge.svg" alt="Docs"></a>
</p>
</div>
<!-- markdownlint-enable -->
**_notion-sdk-py_ is a simple and easy to use client library for the official
[Notion API](https://developers.notion.com/).**
It is meant to be a Python version of the reference [JavaScript SDK](https://github.com/makenotion/notion-sdk-js),
so usage should be very similar between both. 😊 (If not, please open an issue
or PR!)
> 📢 **Announcement** (28-12-2023) — Release 2.2.1 is out and fixes iteration helpers.
>
> What's new in 2.2.0 (26-12-2023):
>
> * Icons and covers can now be removed from pages.
> * `filter_properties` has been added to `notion.pages.retrieve`.
> * You can now pass your own `start_cursor` in the iteration helpers.
<!-- markdownlint-disable -->
## Installation
<!-- markdownlint-enable -->
```shell
pip install notion-client
```
## Usage
> Use Notion's [Getting Started Guide](https://developers.notion.com/docs/getting-started)
> to get set up to use Notion's API.
Import and initialize a client using an **integration token** or an
OAuth **access token**.
```python
import os
from notion_client import Client
notion = Client(auth=os.environ["NOTION_TOKEN"])
```
In an asyncio environment, use the asynchronous client instead:
```python
from notion_client import AsyncClient
notion = AsyncClient(auth=os.environ["NOTION_TOKEN"])
```
Make a request to any Notion API endpoint.
> See the complete list of endpoints in the [API reference](https://developers.notion.com/reference).
```python
from pprint import pprint
list_users_response = notion.users.list()
pprint(list_users_response)
```
or with the asynchronous client:
```python
list_users_response = await notion.users.list()
pprint(list_users_response)
```
This would output something like:
```text
{'results': [{'avatar_url': 'https://secure.notion-static.com/e6a352a8-8381-44d0-a1dc-9ed80e62b53d.jpg',
'id': 'd40e767c-d7af-4b18-a86d-55c61f1e39a4',
'name': 'Avocado Lovelace',
'object': 'user',
'person': {'email': 'avo@example.org'},
'type': 'person'},
...]}
```
All API endpoints are available in both the synchronous and asynchronous clients.
Endpoint parameters are grouped into a single object. You don't need to remember
which parameters go in the path, query, or body.
```python
my_page = notion.databases.query(
**{
"database_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
"filter": {
"property": "Landmark",
"rich_text": {
"contains": "Bridge",
},
},
}
)
```
### Handling errors
If the API returns an unsuccessful response, an `APIResponseError` will be raised.
The error contains properties from the response, and the most helpful is `code`.
You can compare `code` to the values in the `APIErrorCode` object to avoid
misspelling error codes.
```python
import logging
from notion_client import APIErrorCode, APIResponseError
try:
my_page = notion.databases.query(
**{
"database_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
"filter": {
"property": "Landmark",
"rich_text": {
"contains": "Bridge",
},
},
}
)
except APIResponseError as error:
if error.code == APIErrorCode.ObjectNotFound:
... # For example: handle by asking the user to select a different database
else:
# Other error handling code
logging.error(error)
```
### Logging
The client emits useful information to a logger. By default, it only emits warnings
and errors.
If you're debugging an application, and would like the client to log request & response
bodies, set the `log_level` option to `logging.DEBUG`.
```python
notion = Client(
auth=os.environ["NOTION_TOKEN"],
log_level=logging.DEBUG,
)
```
You may also set a custom `logger` to emit logs to a destination other than `stdout`.
Have a look at [Python's logging cookbook](https://docs.python.org/3/howto/logging-cookbook.html)
if you want to create your own logger.
### Client options
`Client` and `AsyncClient` both support the following options on initialization.
These options are all keys in the single constructor parameter.
<!-- markdownlint-disable -->
| Option | Default value | Type | Description |
|--------|---------------|---------|-------------|
| `auth` | `None` | `string` | Bearer token for authentication. If left undefined, the `auth` parameter should be set on each request. |
| `log_level` | `logging.WARNING` | `int` | Verbosity of logs the instance will produce. By default, logs are written to `stdout`.
| `timeout_ms` | `60_000` | `int` | Number of milliseconds to wait before emitting a `RequestTimeoutError` |
| `base_url` | `"https://api.notion.com"` | `string` | The root URL for sending API requests. This can be changed to test with a mock server. |
| `logger` | Log to console | `logging.Logger` | A custom logger. |
### Full API responses
The following functions can distinguish between full and partial API responses.
| Function | Purpose |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `is_full_page` | Determine whether an object is a full [Page object](https://developers.notion.com/reference/page) |
| `is_full_block` | Determine whether an object is a full [Block object](https://developers.notion.com/reference/block) |
| `is_full_database` | Determine whether an object is a full [Database object](https://developers.notion.com/reference/database) |
| `is_full_page_or_database` | Determine whether an object is a full [Page object](https://developers.notion.com/reference/page) or [Database object](https://developers.notion.com/reference/database) |
| `is_full_user` | Determine whether an object is a full [User object](https://developers.notion.com/reference/user) |
| `is_full_comment` | Determine whether an object is a full [Comment object](https://developers.notion.com/reference/comment-object) |
<!-- markdownlint-enable -->
```python
from notion_client.helpers import is_full_page
full_or_partial_pages = await notion.databases.query(
database_id="897e5a76-ae52-4b48-9fdf-e71f5945d1af"
)
for page in full_or_partial_pages["results"]:
if not is_full_page_or_database(page):
continue
print(f"Created at: {page['created_time']}")
```
### Utility functions
These functions can be helpful for dealing with any of the paginated APIs.
`iterate_paginated_api(function, **kwargs)` and its async version
`async_iterate_paginated_api(function, **kwargs)` turn any paginated API into a generator.
The `function` parameter must accept a `start_cursor` argument. Example: `notion.blocks.children.list`.
```python
from notion_client.helpers import iterate_paginated_api
for block in iterate_paginated_api(
notion.databases.query, database_id="897e5a76-ae52-4b48-9fdf-e71f5945d1af"
):
# Do something with block.
...
```
If you don't need a generator, `collect_paginated_api(function, **kwargs)` and
its async version `async_collect_paginated_api(function, **kwargs)` have the
same behavior than the previous functions, but return a list of all results
from the paginated API.
```python
from notion_client.helpers import collect_paginated_api
all_results = collect_paginated_api(
notion.databases.query, database_id="897e5a76-ae52-4b48-9fdf-e71f5945d1af"
)
```
## Testing
Run the tests with the `pytest` command. If you want to test against all Python
versions, you can run `tox` instead.
The tests are using `pytest-vcr`'s cassettes for simulating requests to the
Notion API. To create new tests or run them without cassettes, you need to set
up the environment variables `NOTION_TOKEN` and `NOTION_TEST_PAGE_ID` (a page
where your integration has all the capabilities enabled).
The code will use the page at `NOTION_TEST_PAGE_ID` to generate a temporary
environment with the Notion objects to be tested, which will be deleted
at the end of the session.
## Requirements
This package supports the following minimum versions:
* Python >= 3.7
* httpx >= 0.15.0
Earlier versions may still work, but we encourage people building new applications
to upgrade to the current stable.
## Getting help
If you want to submit a feature request for Notion's API, or are experiencing
any issues with the API platform, please email `developers@makenotion.com`.
If you found a bug with the library, please [submit an issue](https://github.com/ramnes/notion-sdk-py/issues).
Raw data
{
"_id": null,
"home_page": "https://github.com/ramnes/notion-sdk-py",
"name": "notion-client",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7, <4",
"maintainer_email": "",
"keywords": "",
"author": "Guillaume Gelin",
"author_email": "contact@ramnes.eu",
"download_url": "https://files.pythonhosted.org/packages/cd/95/6e0d1cb377a296ecc940ad6c8662b6c18cada6b69cec1742295e9228a7d1/notion-client-2.2.1.tar.gz",
"platform": null,
"description": "<!-- markdownlint-disable -->\n![notion-sdk-py](https://socialify.git.ci/ramnes/notion-sdk-py/image?font=Bitter&language=1&logo=https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2F4%2F45%2FNotion_app_logo.png&owner=1&pattern=Circuit%20Board&theme=Light)\n\n<div align=\"center\">\n <p>\n <a href=\"https://pypi.org/project/notion-client\"><img src=\"https://img.shields.io/pypi/v/notion-client.svg\" alt=\"PyPI\"></a>\n <a href=\"tox.ini\"><img src=\"https://img.shields.io/pypi/pyversions/notion-client\" alt=\"Supported Python Versions\"></a>\n <br/>\n <a href=\"LICENSE\"><img src=\"https://img.shields.io/github/license/ramnes/notion-sdk-py\" alt=\"License\"></a>\n <a href=\"https://github.com/ambv/black\"><img src=\"https://img.shields.io/badge/code%20style-black-black\" alt=\"Code style\"></a>\n <a href=\"https://codecov.io/github/ramnes/notion-sdk-py\"><img src=\"https://codecov.io/gh/ramnes/notion-sdk-py/branch/main/graphs/badge.svg\" alt=\"Coverage\"></a>\n <a href=\"https://snyk.io/advisor/python/notion-client\"><img src=\"https://snyk.io/advisor/python/notion-client/badge.svg\" alt=\"Package health\"></a>\n <br/>\n <a href=\"https://github.com/ramnes/notion-sdk-py/actions/workflows/quality.yml\"><img src=\"https://github.com/ramnes/notion-sdk-py/actions/workflows/quality.yml/badge.svg\" alt=\"Code Quality\"></a>\n <a href=\"https://github.com/ramnes/notion-sdk-py/actions/workflows/test.yml\"><img src=\"https://github.com/ramnes/notion-sdk-py/actions/workflows/test.yml/badge.svg\" alt=\"Tests\"></a>\n <a href=\"https://github.com/ramnes/notion-sdk-py/actions/workflows/docs.yml\"><img src=\"https://github.com/ramnes/notion-sdk-py/actions/workflows/docs.yml/badge.svg\" alt=\"Docs\"></a>\n </p>\n</div>\n<!-- markdownlint-enable -->\n\n**_notion-sdk-py_ is a simple and easy to use client library for the official\n[Notion API](https://developers.notion.com/).**\n\nIt is meant to be a Python version of the reference [JavaScript SDK](https://github.com/makenotion/notion-sdk-js),\nso usage should be very similar between both. \ud83d\ude0a (If not, please open an issue\nor PR!)\n\n> \ud83d\udce2 **Announcement** (28-12-2023) \u2014 Release 2.2.1 is out and fixes iteration helpers.\n>\n> What's new in 2.2.0 (26-12-2023):\n>\n> * Icons and covers can now be removed from pages.\n> * `filter_properties` has been added to `notion.pages.retrieve`.\n> * You can now pass your own `start_cursor` in the iteration helpers.\n\n<!-- markdownlint-disable -->\n## Installation\n<!-- markdownlint-enable -->\n```shell\npip install notion-client\n```\n\n## Usage\n\n> Use Notion's [Getting Started Guide](https://developers.notion.com/docs/getting-started)\n> to get set up to use Notion's API.\n\nImport and initialize a client using an **integration token** or an\nOAuth **access token**.\n\n```python\nimport os\nfrom notion_client import Client\n\nnotion = Client(auth=os.environ[\"NOTION_TOKEN\"])\n```\n\nIn an asyncio environment, use the asynchronous client instead:\n\n```python\nfrom notion_client import AsyncClient\n\nnotion = AsyncClient(auth=os.environ[\"NOTION_TOKEN\"])\n```\n\nMake a request to any Notion API endpoint.\n\n> See the complete list of endpoints in the [API reference](https://developers.notion.com/reference).\n\n```python\nfrom pprint import pprint\n\nlist_users_response = notion.users.list()\npprint(list_users_response)\n```\n\nor with the asynchronous client:\n\n```python\nlist_users_response = await notion.users.list()\npprint(list_users_response)\n```\n\nThis would output something like:\n\n```text\n{'results': [{'avatar_url': 'https://secure.notion-static.com/e6a352a8-8381-44d0-a1dc-9ed80e62b53d.jpg',\n 'id': 'd40e767c-d7af-4b18-a86d-55c61f1e39a4',\n 'name': 'Avocado Lovelace',\n 'object': 'user',\n 'person': {'email': 'avo@example.org'},\n 'type': 'person'},\n ...]}\n```\n\nAll API endpoints are available in both the synchronous and asynchronous clients.\n\nEndpoint parameters are grouped into a single object. You don't need to remember\nwhich parameters go in the path, query, or body.\n\n```python\nmy_page = notion.databases.query(\n **{\n \"database_id\": \"897e5a76-ae52-4b48-9fdf-e71f5945d1af\",\n \"filter\": {\n \"property\": \"Landmark\",\n \"rich_text\": {\n \"contains\": \"Bridge\",\n },\n },\n }\n)\n```\n\n### Handling errors\n\nIf the API returns an unsuccessful response, an `APIResponseError` will be raised.\n\nThe error contains properties from the response, and the most helpful is `code`.\nYou can compare `code` to the values in the `APIErrorCode` object to avoid\nmisspelling error codes.\n\n```python\nimport logging\nfrom notion_client import APIErrorCode, APIResponseError\n\ntry:\n my_page = notion.databases.query(\n **{\n \"database_id\": \"897e5a76-ae52-4b48-9fdf-e71f5945d1af\",\n \"filter\": {\n \"property\": \"Landmark\",\n \"rich_text\": {\n \"contains\": \"Bridge\",\n },\n },\n }\n )\nexcept APIResponseError as error:\n if error.code == APIErrorCode.ObjectNotFound:\n ... # For example: handle by asking the user to select a different database\n else:\n # Other error handling code\n logging.error(error)\n```\n\n### Logging\n\nThe client emits useful information to a logger. By default, it only emits warnings\nand errors.\n\nIf you're debugging an application, and would like the client to log request & response\nbodies, set the `log_level` option to `logging.DEBUG`.\n\n```python\nnotion = Client(\n auth=os.environ[\"NOTION_TOKEN\"],\n log_level=logging.DEBUG,\n)\n```\n\nYou may also set a custom `logger` to emit logs to a destination other than `stdout`.\nHave a look at [Python's logging cookbook](https://docs.python.org/3/howto/logging-cookbook.html)\nif you want to create your own logger.\n\n### Client options\n\n`Client` and `AsyncClient` both support the following options on initialization.\nThese options are all keys in the single constructor parameter.\n\n<!-- markdownlint-disable -->\n| Option | Default value | Type | Description |\n|--------|---------------|---------|-------------|\n| `auth` | `None` | `string` | Bearer token for authentication. If left undefined, the `auth` parameter should be set on each request. |\n| `log_level` | `logging.WARNING` | `int` | Verbosity of logs the instance will produce. By default, logs are written to `stdout`.\n| `timeout_ms` | `60_000` | `int` | Number of milliseconds to wait before emitting a `RequestTimeoutError` |\n| `base_url` | `\"https://api.notion.com\"` | `string` | The root URL for sending API requests. This can be changed to test with a mock server. |\n| `logger` | Log to console | `logging.Logger` | A custom logger. |\n\n### Full API responses\n\nThe following functions can distinguish between full and partial API responses.\n\n| Function | Purpose |\n| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `is_full_page` | Determine whether an object is a full [Page object](https://developers.notion.com/reference/page) |\n| `is_full_block` | Determine whether an object is a full [Block object](https://developers.notion.com/reference/block) |\n| `is_full_database` | Determine whether an object is a full [Database object](https://developers.notion.com/reference/database) |\n| `is_full_page_or_database` | Determine whether an object is a full [Page object](https://developers.notion.com/reference/page) or [Database object](https://developers.notion.com/reference/database) |\n| `is_full_user` | Determine whether an object is a full [User object](https://developers.notion.com/reference/user) |\n| `is_full_comment` | Determine whether an object is a full [Comment object](https://developers.notion.com/reference/comment-object) |\n<!-- markdownlint-enable -->\n\n```python\nfrom notion_client.helpers import is_full_page\n\nfull_or_partial_pages = await notion.databases.query(\n database_id=\"897e5a76-ae52-4b48-9fdf-e71f5945d1af\"\n)\n\nfor page in full_or_partial_pages[\"results\"]:\n if not is_full_page_or_database(page):\n continue\n print(f\"Created at: {page['created_time']}\")\n```\n\n### Utility functions\n\nThese functions can be helpful for dealing with any of the paginated APIs.\n\n`iterate_paginated_api(function, **kwargs)` and its async version\n`async_iterate_paginated_api(function, **kwargs)` turn any paginated API into a generator.\n\nThe `function` parameter must accept a `start_cursor` argument. Example: `notion.blocks.children.list`.\n\n```python\nfrom notion_client.helpers import iterate_paginated_api\n\nfor block in iterate_paginated_api(\n notion.databases.query, database_id=\"897e5a76-ae52-4b48-9fdf-e71f5945d1af\"\n):\n # Do something with block.\n ...\n```\n\nIf you don't need a generator, `collect_paginated_api(function, **kwargs)` and\nits async version `async_collect_paginated_api(function, **kwargs)` have the\nsame behavior than the previous functions, but return a list of all results\nfrom the paginated API.\n\n```python\nfrom notion_client.helpers import collect_paginated_api\n\nall_results = collect_paginated_api(\n notion.databases.query, database_id=\"897e5a76-ae52-4b48-9fdf-e71f5945d1af\"\n)\n```\n\n## Testing\n\nRun the tests with the `pytest` command. If you want to test against all Python\nversions, you can run `tox` instead.\n\nThe tests are using `pytest-vcr`'s cassettes for simulating requests to the\nNotion API. To create new tests or run them without cassettes, you need to set\nup the environment variables `NOTION_TOKEN` and `NOTION_TEST_PAGE_ID` (a page\nwhere your integration has all the capabilities enabled).\n\nThe code will use the page at `NOTION_TEST_PAGE_ID` to generate a temporary\nenvironment with the Notion objects to be tested, which will be deleted\nat the end of the session.\n\n## Requirements\n\nThis package supports the following minimum versions:\n\n* Python >= 3.7\n* httpx >= 0.15.0\n\nEarlier versions may still work, but we encourage people building new applications\nto upgrade to the current stable.\n\n## Getting help\n\nIf you want to submit a feature request for Notion's API, or are experiencing\nany issues with the API platform, please email `developers@makenotion.com`.\n\nIf you found a bug with the library, please [submit an issue](https://github.com/ramnes/notion-sdk-py/issues).\n",
"bugtrack_url": null,
"license": "",
"summary": "Python client for the official Notion API",
"version": "2.2.1",
"project_urls": {
"Homepage": "https://github.com/ramnes/notion-sdk-py"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "225e977505b17c5528cffaaf561de46f58fa546345ae75866e3985039aaa991d",
"md5": "1df1c8a82ffbdf3412f3a60cddb29d3b",
"sha256": "4ecf9ec527a124462f7bd407d9c9ead9853a9b2c8f00e56f3fa8fb15106ad871"
},
"downloads": -1,
"filename": "notion_client-2.2.1-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "1df1c8a82ffbdf3412f3a60cddb29d3b",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": ">=3.7, <4",
"size": 13983,
"upload_time": "2023-12-28T11:31:34",
"upload_time_iso_8601": "2023-12-28T11:31:34.498784Z",
"url": "https://files.pythonhosted.org/packages/22/5e/977505b17c5528cffaaf561de46f58fa546345ae75866e3985039aaa991d/notion_client-2.2.1-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "cd956e0d1cb377a296ecc940ad6c8662b6c18cada6b69cec1742295e9228a7d1",
"md5": "0c15cc53994bd3d302043090e55f7ac6",
"sha256": "3827e381ccb5a21aeb606686787edfb6c7a10681cb3507c4d606a1918e791061"
},
"downloads": -1,
"filename": "notion-client-2.2.1.tar.gz",
"has_sig": false,
"md5_digest": "0c15cc53994bd3d302043090e55f7ac6",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7, <4",
"size": 19857,
"upload_time": "2023-12-28T11:31:37",
"upload_time_iso_8601": "2023-12-28T11:31:37.347120Z",
"url": "https://files.pythonhosted.org/packages/cd/95/6e0d1cb377a296ecc940ad6c8662b6c18cada6b69cec1742295e9228a7d1/notion-client-2.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-28 11:31:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ramnes",
"github_project": "notion-sdk-py",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"tox": true,
"lcname": "notion-client"
}