Skip to content

Commit

Permalink
#27 properties retrieving algo changes
Browse files Browse the repository at this point in the history
  • Loading branch information
lastorel committed Jul 28, 2022
1 parent 99d4c00 commit 88a50ca
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 16 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Changelog

## v1.3.0

- \#27: Switched from `2022-02-22` to `2022-06-28` version of Notion API
- `Request()` (internal) method argument added
- \#27: Fix of parent object hierarchy
- \#27: `models.Block` now has non-empty `parent` attr
- `models.Database`: `is_inline` attr added
- `Notion()`: new optional arg `version` added to customize API interaction
- \#27: You must retrieve Page properties manually. `.get_page_properties` method added

### Breaking changes

- `Request()` method now looks for positional argument `api` for getting version (internal method)
- Page has title=`unknown` until you retrieve its properties
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Client is built with its own object model based on API
So if you are using **notion.so** and want to automate some stuff with the original API, you're welcome!
You can read any available data, create basic models, and even work with databases.

Current Notion API version = **"2022-02-22"**
Current Notion API version = **"2022-06-28"**

_*does not use notion-sdk-py client_

Expand Down Expand Up @@ -146,6 +146,8 @@ There is a list of available methods for communicate with **api.notion.com**. Th

`.get_page_property(property_id, id_, limit)` - Retrieve a page property item.

`.get_page_properties(title_only, obj)` - Retrieve the title or all properties of current Page or Page `obj`

`.db_query(id_, limit, filter_, sorts)` - Query Database.

`.db_filter(...see desc...)` - Query Database.
Expand Down Expand Up @@ -191,6 +193,7 @@ There are classes **based on API** structures:
- use `.db_filter()` to get database content with filtering and/or sorting
- `Page` based on [Page object](https://developers.notion.com/reference/page)
- You can create object `Page.create(...)` and/or use `.page_create(...)` API method
- use `.get_page_properties()` to retrieve page title and other `PropertyValue`-s
- use `.page_update()` method to modify attributes or delete the page
- use `.get_block_children()` to get page content (without nested blocks) (it will be `BlockArray`)
- use `.get_block_children_recursive()` to get page content with nested blocks
Expand Down
32 changes: 30 additions & 2 deletions pytion/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,38 @@ def get_page_property(self, property_id: str, id_: Optional[str] = None, limit:
return None
if isinstance(id_, str) and "-" in id_:
id_ = id_.replace("-", "")
if self.obj:
if self.obj and not id_:
id_ = self.obj.id
property_obj = self.api.session.method(
method="get", path=self.name, id_=id_, after_path="properties/"+property_id, limit=limit
)
return Element(api=self.api, name=f"pages/{id_}/properties", obj=PropertyValue(property_obj, property_id))

def get_page_properties(self, title_only: bool = False, obj: Optional[Page] = None) -> None:
"""
Page properties must be retrieved using the page properties endpoint. (c)
after retrieving a Page object you can retrieve its properties
obj or self.obj must be a Page
:return:
"""
if not obj:
obj = self.obj
if obj and isinstance(obj, Page):
for prop in obj.properties:
# Skip already retrieved properties
if isinstance(obj.properties[prop], PropertyValue):
continue
prop_id = obj.properties[prop].id
if title_only and prop_id != "title":
continue
result = self.get_page_property(prop_id, id_=obj.id)
obj.properties[prop] = result.obj
if prop_id == "title":
obj.title = result.obj.value if result.obj.value else ""
return
logger.warning("You must provide a Page to retrieve properties")

def db_query(
self,
id_: Optional[str] = None,
Expand All @@ -246,7 +271,10 @@ def db_query(
)
if r["object"] != "list":
return None
return Element(api=self.api, name="pages", obj=PageArray(r["results"]))
pa = Element(api=self.api, name="pages", obj=PageArray(r["results"]))
for p in pa.obj:
pa.get_page_properties(title_only=True, obj=p)
return pa

def db_filter(self, title: str = None, **kwargs) -> Optional[Element]:
"""
Expand Down
11 changes: 3 additions & 8 deletions pytion/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def format_iso_time(cls, time: str) -> Optional[datetime]:

class Property(object):
def __init__(self, data: Dict[str, str]):
self.to_delete = True if data.get("type") is None else False
self.to_delete = True if data.get("type", False) is None else False
self.id: str = data.get("id")
self.type: str = data.get("type", "")
self.name: str = data.get("name")
Expand Down Expand Up @@ -509,15 +509,10 @@ def __init__(self, **kwargs) -> None:
self.url: str = kwargs.get("url")
self.children = kwargs["children"] if "children" in kwargs else LinkTo(block=self)
self.properties = {
name: (PropertyValue(data, name) if not isinstance(data, PropertyValue) else data)
name: (Property(data) if not isinstance(data, PropertyValue) else data)
for name, data in kwargs["properties"].items()
}
for p in self.properties.values():
if "title" in p.type:
self.title = p.value
break
else:
self.title = None
self.title = "unknown"

def __str__(self):
return str(self.title)
Expand Down
4 changes: 3 additions & 1 deletion tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ def page_for_pages(no):

@pytest.fixture(scope="session")
def page_for_updates(no):
return no.pages.get("36223246a20e42df8f9b354ed1f11d75")
page = no.pages.get("36223246a20e42df8f9b354ed1f11d75")
page.get_page_properties()
return page
45 changes: 41 additions & 4 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def test_get__page(self, root_page):
page = root_page
assert isinstance(page.obj, Page), "get of .pages. must return Page object"
assert page.obj.id == "878d628488d94894ab14f9b872cd6870"
page.get_page_properties()
assert str(page.obj.title) == "Pytion Tests"

def test_get__block(self, no):
Expand Down Expand Up @@ -69,6 +70,7 @@ def test_get_parent__block2(self, no):
parent_block = no.blocks.get_parent("8a920ba7dc1d4961811e5c82b28028ed") # Hello! How are you?
assert isinstance(parent_block.obj, Page)
assert parent_block.obj.id == "82ee5677402f44819a5da3302273400a"
parent_block.get_page_properties()
assert str(parent_block.obj) == "Page with some texts"

def test_get_parent__page(self, no):
Expand All @@ -91,6 +93,7 @@ def test_get_parent__block_obj(self, no):
parent_block = block.get_parent()
assert isinstance(parent_block.obj, Page)
assert parent_block.obj.id == "82ee5677402f44819a5da3302273400a"
parent_block.get_page_properties()
assert str(parent_block.obj) == "Page with some texts"

def test_get_parent__page_obj(self, no): # Database is the parent of this page
Expand All @@ -103,15 +106,17 @@ def test_get_parent__page_obj(self, no): # Database is the parent of this page
def test_get_parent__database_obj(self, little_database):
database = little_database # Little Database
parent_page_block = database.get_parent()
assert isinstance(parent_page_block.obj, Block)
assert isinstance(parent_page_block.obj, Page)
assert parent_page_block.obj.id == "878d628488d94894ab14f9b872cd6870"
assert parent_page_block.obj.text == "Pytion Tests"
parent_page_block.get_page_properties()
assert str(parent_page_block.obj) == "Pytion Tests"

def test_get_parent__child_page(self, no):
child_page = no.blocks.get("878d628488d94894ab14f9b872cd6870") # root page
page = child_page.get_parent()
assert isinstance(page.obj, Page)
assert page.obj.id == "878d628488d94894ab14f9b872cd6870"
page.get_page_properties()
assert str(page.obj.title) == "Pytion Tests"

def test_get_parent__child_database(self, no):
Expand Down Expand Up @@ -244,6 +249,26 @@ def test_get_page_property__bad_page(self, no):
with pytest.raises(ObjectNotFound):
no.pages.get_page_property("%7Dma%3F", "b85877eaf7bf4245a8c5218055eeb81a")

def test_get_page_properties(self, no):
page = no.pages.get("b85877eaf7bf4245a8c5218055eeb81f") # Parent testing page
assert isinstance(page.obj, Page)
assert str(page.obj) == "unknown"
assert isinstance(page.obj.properties["Done"], Property)
page.get_page_properties()
assert isinstance(page.obj.properties["Done"], PropertyValue)
assert page.obj.properties["Digit"].value == 2
assert "tag1" in page.obj.properties["Tags"].value

def test_get_page_properties__title(self, no):
page = no.pages.get("b85877eaf7bf4245a8c5218055eeb81f") # Parent testing page
assert isinstance(page.obj, Page)
assert str(page.obj) == "unknown"
assert isinstance(page.obj.properties["Done"], Property)
page.get_page_properties(title_only=True)
assert hasattr(page.obj.properties["by"], "value") is False
assert isinstance(page.obj.properties["Done"], Property)
assert str(page.obj.title) == "Parent testing page"

def test_db_query__id(self, no):
pages = no.databases.db_query("0e9539099cff456d89e44684d6b6c701") # Little Database
assert isinstance(pages.obj, PageArray)
Expand Down Expand Up @@ -322,6 +347,7 @@ def test_db_filter__no_tags(self, little_database):

def test_db_filter__tag_property_obj(self, no, little_database):
page = no.pages.get("c2fc6b3dc3d244e9be2a3d28b26082bf") # Untitled
page.get_page_properties()
my_prop = page.obj.properties["Tags"]
pages = little_database.db_filter(property_obj=my_prop)
assert isinstance(pages.obj, PageArray)
Expand Down Expand Up @@ -422,6 +448,7 @@ def test_page_create__into_page(self, no, page_for_pages):
parent = LinkTo(from_object=page_for_pages.obj)
page = no.pages.page_create(parent=parent, title="Page 1")
assert isinstance(page.obj, Page)
page.get_page_properties(title_only=True)
assert str(page.obj.title) == "Page 1"
# delete section
delete_page = page.page_update(archived=True)
Expand All @@ -431,6 +458,7 @@ def test_page_create__into_database(self, no):
parent = LinkTo.create(database_id="35f50aa293964b0d93e09338bc980e2e") # Database for creating pages
page = no.pages.page_create(parent=parent, title="Page 2")
assert isinstance(page.obj, Page)
page.get_page_properties(title_only=True)
assert str(page.obj.title) == "Page 2"
# delete section
delete_page = page.page_update(archived=True)
Expand All @@ -445,6 +473,7 @@ def test_page_create__into_database_props(self, no):
}
page = no.pages.page_create(parent=parent, properties=props, title="Page 3")
assert isinstance(page.obj, Page)
page.get_page_properties(title_only=True)
assert str(page.obj.title) == "Page 3"
# delete section
delete_page = page.page_update(archived=True)
Expand All @@ -455,6 +484,7 @@ def test_page_create__with_children(self, no, page_for_pages):
child = Block.create("Hello, World!")
page = no.pages.page_create(parent=parent, title="Page 4", children=[child])
assert isinstance(page.obj, Page)
page.get_page_properties(title_only=True)
assert str(page.obj.title) == "Page 4"
blocks = page.get_block_children()
assert isinstance(blocks.obj, BlockArray)
Expand All @@ -470,6 +500,7 @@ def test_page_create__from_obj(self, no, page_for_pages):
page_obj = Page.create(parent=parent, title="Page 5")
page = no.pages.page_create(page_obj=page_obj)
assert isinstance(page.obj, Page)
page.get_page_properties(title_only=True)
assert str(page.obj.title) == "Page 5"
# delete section
delete_page = page.page_update(archived=True)
Expand All @@ -480,12 +511,15 @@ def test_page_update__rename(self, page_for_updates):
new_name = "Updating for page"
page = page_for_updates.page_update(title=new_name)
assert isinstance(page.obj, Page)
page.get_page_properties(title_only=True)
assert str(page.obj.title) == new_name

old_page = page.page_update(title=RichTextArray.create(old_name))
old_page.get_page_properties(title_only=True)
assert str(old_page.obj.title) == old_name

def test_page_update__change_props(self, page_for_updates):
page_for_updates.get_page_properties()
old_props = page_for_updates.obj.properties
new_props = {
"Tags": PropertyValue.create("multi_select", ["tag2"]),
Expand All @@ -494,10 +528,12 @@ def test_page_update__change_props(self, page_for_updates):
}
page = page_for_updates.page_update(properties=new_props)
assert isinstance(page.obj, Page)
page.get_page_properties()
assert "tag2" in page.obj.properties["Tags"].value
assert page.obj.properties["done"].value is False

old_page = page.page_update(properties=old_props)
old_page.get_page_properties()
assert "tag1" in old_page.obj.properties["Tags"].value
assert old_page.obj.properties["done"].value is True

Expand Down Expand Up @@ -580,9 +616,10 @@ def test_block_append__many(self, no):
def test_from_linkto__base(self, no):
link = LinkTo.create(page_id="878d628488d94894ab14f9b872cd6870")
page = no.pages.from_linkto(link)
assert isinstance(page.obj, Block)
assert isinstance(page.obj, Page)
assert page.obj.id == "878d628488d94894ab14f9b872cd6870"
assert str(page.obj.text) == "Pytion Tests"
page.get_page_properties(title_only=True)
assert str(page.obj) == "Pytion Tests"

def test_from_linkto__child(self, page_some_texts):
child = page_some_texts.from_linkto(page_some_texts.obj.children)
Expand Down

0 comments on commit 88a50ca

Please sign in to comment.