jamalex / notion-py

Unofficial Python API client for Notion.so
MIT License
4.3k stars 475 forks source link

HTTP Invalid Input #357

Open Army-py opened 3 years ago

Army-py commented 3 years ago
from notion.client import NotionClient

class Notion:
    def __init__(self):
        self.client = NotionClient(token_v2="token")

        self.table = self.client.get_collection_view("https://www.notion.so/7d[...]?v=eb[...]")

    def test(self):
        print(self.table)

n = Notion()
n.test()
Traceback (most recent call last):
  File "c:/Users/flori/Desktop/code/notion_shards.py", line 17, in <module>
    n = Notion()
  File "c:/Users/flori/Desktop/code/notion_shards.py", line 9, in __init__
    self.table = self.client.get_collection_view("https://www.notion.so/7d[...]?v=eb[...]")
  File "C:\Users\flori\AppData\Local\Programs\Python\Python38\lib\site-packages\notion\client.py", line 216, in get_collection_view
    collection = self.get_block(
  File "C:\Users\flori\AppData\Local\Programs\Python\Python38\lib\site-packages\notion\client.py", line 169, in get_block
    block = self.get_record_data("block", block_id, force_refresh=force_refresh)
  File "C:\Users\flori\AppData\Local\Programs\Python\Python38\lib\site-packages\notion\client.py", line 162, in get_record_data
    return self._store.get(table, id, force_refresh=force_refresh)
  File "C:\Users\flori\AppData\Local\Programs\Python\Python38\lib\site-packages\notion\store.py", line 184, in get
    self.call_load_page_chunk(id)
  File "C:\Users\flori\AppData\Local\Programs\Python\Python38\lib\site-packages\notion\store.py", line 286, in call_load_page_chunk
    recordmap = self._client.post("loadPageChunk", data).json()["recordMap"]
  File "C:\Users\flori\AppData\Local\Programs\Python\Python38\lib\site-packages\notion\client.py", line 260, in post
    raise HTTPError(
requests.exceptions.HTTPError: Invalid input.
ssvaddiparthy commented 3 years ago

looks like notionhq changed something on the backend :/

CobeA527 commented 3 years ago

Same problem here ..:(

benpence commented 3 years ago

I'm not sure this is related, but I noticed that if you visit a page's parent pages starting from the root, you are able to load it properly. So I have something like this in my code now:

ancestors = {
    'ded42785910b43349e7a406181f64475': [
        '38ec63708e904d41a84c2985d745ee82',
        'd1498e133e7d413085c936435449bdbb',
    ],
    # ...
}

def visit_ancestors(client, page_id):
    for ancestor_page_id in ancestors[page_id]:
        client.get_block(ancestor_page_id).children

visit_ancestors(notion_client, page_id)
page = client.get_block(page_id)
# ...

(except in reality, ancestors is not a dict but a call to a DB that I populate nightly with all ancestors for all my pages :sob:)

ssvaddiparthy commented 3 years ago

I have rewritten my use cases to consume the API directly.

benpence commented 3 years ago

Ah nice! I haven't looked at the official API much. What is feature parity like? Is it similar enough?

ssvaddiparthy commented 3 years ago

so the official API is very powerful and flexible. I am actually taking a stab at may be redoing this library to use the API.

benpence commented 3 years ago

@ssvaddiparthy thanks that would be super awesome! I have felt similarly, but for now my fix above sorta works for me, so I've kind of de-prioritized it considerably.

Last year, I wrote a layer on top of this unofficial API, e.g.

import abc
from dataclasses import dataclass
from notion import block

class Block(abc.ABC):
    @abc.abstractmethod
    def append_to_page(self, page: block.Block) -> None:
        pass

@dataclass(frozen=True)
class PageBlock(Block):
    title: str
    children: Sequence[Block]
    icon: Optional[str] = None

    def append_to_page(self, page: block.Block) -> None:
        new_page = page.children.add_new(block.PageBlock, title=self.title)

        if self.icon:
            new_page.icon = self.icon

        for child in self.children:
            child.append_to_page(new_page)

@dataclass(frozen=True)
class VideoBlock(Block):
    filepath: str

    def append_to_page(self, page: block.Block) -> None:
        page.children.add_new(block.VideoBlock).upload_file(self.filepath)

# ...

def append_to_page(new_block: Block, page_id: str) -> str:
      page = client.get_block(page_id)
      new_block.append_to_page(page)
      return page.children[-1].id

so I could do something like

append_to_page(
    new_block=PageBlock(
        title='Blah',
        children=[
              TextBlock('Foo'),
              TextBlock('Bar'),
              VideoBlock(filepath=local_video_path),
          ],
    ),
    page_id='1da9b81c7b964a6a9fb3187ba91d2f8b',
))

But it's sort of specialized for my use case, which is to always create new pages and/or append or prepend to pages. I never read data from Notion.