jheddings / notional

A high level interface and object model for the Notion SDK.
https://jheddings.github.io/notional/
MIT License
98 stars 16 forks source link

Updating page properties doesn't work if a formula property is present #59

Open FlorianWilhelm opened 2 years ago

FlorianWilhelm commented 2 years ago

To determine to current version, run python -m notional

Notional Version: current main brunch, i.e. notional.__version__ shows 0.4.1-73c5bc5, it seems like this should have been increased to 0.4.2 in the last release?

Description

Updating a page doesn't work if the page contains a formula property.

Steps To Reproduce

notion_orm = notional.connect(auth=AUTH_TOKEN)
query = notion_orm.databases.query(db['id']).sort(property="Name", direction=notional.query.SortDirection.ASCENDING)
p = query.first()
notion_orm.pages.update(p)

Expected Behavior

Since we are not changing anything, calling notion_orm.pages.update(p) should just work. Instead:

---------------------------------------------------------------------------
HTTPStatusError                           Traceback (most recent call last)
File ~/.mambaforge/envs/ultimate-notion/lib/python3.10/site-packages/notion_client/client.py:116, in BaseClient._parse_response(self, response)
    115 try:
--> 116     response.raise_for_status()
    117 except httpx.HTTPStatusError as error:

File ~/.mambaforge/envs/ultimate-notion/lib/python3.10/site-packages/httpx/_models.py:736, in Response.raise_for_status(self)
    735 message = message.format(self, error_type=error_type)
--> 736 raise HTTPStatusError(message, request=request, response=self)

HTTPStatusError: Client error '400 Bad Request' for url 'https://api.notion.com/v1/pages/XXXXXXXXREMOVED'
For more information check: https://httpstatuses.com/400

During handling of the above exception, another exception occurred:

APIResponseError                          Traceback (most recent call last)
Input In [86], in <cell line: 1>()
----> 1 notion_orm.pages.update(p)

File ~/Sources/notional/src/notional/session.py:345, in PagesEndpoint.update(self, page, **properties)
    338     properties = page.properties
    340 props = {
    341     name: value.to_api() if value is not None else None
    342     for name, value in properties.items()
    343 }
--> 345 data = self().update(page.id.hex, properties=props)
    347 return page.refresh(**data)

File ~/.mambaforge/envs/ultimate-notion/lib/python3.10/site-packages/notion_client/api_endpoints.py:218, in PagesEndpoint.update(self, page_id, **kwargs)
    213 def update(self, page_id: str, **kwargs: Any) -> SyncAsync[Any]:
    214     """Update [page property values](https://developers.notion.com/reference/page#property-value-object) for the specified page.
    215 
    216     *[🔗 Endpoint documentation](https://developers.notion.com/reference/patch-page)*
    217     """  # noqa: E501
--> 218     return self.parent.request(
    219         path=f"pages/{page_id}",
    220         method="PATCH",
    221         body=pick(kwargs, "archived", "properties", "icon", "cover"),
    222         auth=kwargs.get("auth"),
    223     )

File ~/.mambaforge/envs/ultimate-notion/lib/python3.10/site-packages/notion_client/client.py:192, in Client.request(self, path, method, query, body, auth)
    190 except httpx.TimeoutException:
    191     raise RequestTimeoutError()
--> 192 return self._parse_response(response)

File ~/.mambaforge/envs/ultimate-notion/lib/python3.10/site-packages/notion_client/client.py:124, in BaseClient._parse_response(self, response)
    122         code = None
    123     if code and is_api_error_code(code):
--> 124         raise APIResponseError(response, body["message"], code)
    125     raise HTTPResponseError(error.response)
    127 body = response.json()

APIResponseError: body failed validation. Fix one:
body.properties.MyFormula.title should be defined, instead was `undefined`.
body.properties.MyFormula.rich_text should be defined, instead was `undefined`.
body.properties.MyFormula.number should be defined, instead was `undefined`.
body.properties.MyFormula.url should be defined, instead was `undefined`.
body.properties.MyFormula.select should be defined, instead was `undefined`.
body.properties.MyFormula.multi_select should be defined, instead was `undefined`.
body.properties.MyFormula.people should be defined, instead was `undefined`.
body.properties.MyFormula.email should be defined, instead was `undefined`.
body.properties.MyFormula.phone_number should be defined, instead was `undefined`.
body.properties.MyFormula.date should be defined, instead was `undefined`.
body.properties.MyFormula.checkbox should be defined, instead was `undefined`.
body.properties.MyFormula.relation should be defined, instead was `undefined`.
body.properties.MyFormula.files should be defined, instead was `undefined`.
body.properties.Level.type should be not present, instead was `"select"`.
body.properties.Level.select should be not present, instead was `{"name":"Advanced","id":"]yHE","color":"blue"}`.
body.properties.Level.name should be defined, instead was `undefined`.
body.properties.Level.start should be defined, instead was `undefined`.

Just removing the property MyFormula from the database fixes this problem. Interesting is that also the property Level seems to be affected when a Formula is present although it's of type select.

Additional Context

jheddings commented 2 years ago

Thanks for the detailed report! I believe this is the same issue as #9 where read-only properties cause the update method to fail. I've been contemplating a rewrite of how Notional handles this, but time has been limited lately 😒

As a workaround, you would need to create a dictionary of properties to update from the pages object. Then you can simply pass that to the update method:

notion_orm.pages.update(p, **props)

It's not a great solution, but might get you moving.

FlorianWilhelm commented 2 years ago

Thanks for the fast reply. I'll try that.

Regarding a proper solution. Wouldn't it help to have some kind of update attribute on all properties that gets set to true when the object is changed? During an update, only those properties with updated=True are transferred.

tyePhDCandy commented 1 year ago

indeed. but it can be easily achieved by building a function based on what we have now. what i want is to update the whole database just using one request to notion server.

jheddings commented 1 year ago

what i want is to update the whole database just using one request to notion server.

Keep in mind that Notional is just a wrapper around the official Notion API. In order to support this, the official API would need to change.