Skip to content

Commit

Permalink
update how database filters children and add version flag (#89)
Browse files Browse the repository at this point in the history
* update how database filters children and add version flag

* update readme

* flake8

* nail down _tuplize

* delete print statements

* change version

* retrieve version from setup.py

* update readme

* Add various features

- add `get_children()` method to databases and pages in order to update `Database._children` and `Page._children` manually
- add `Client.copy_notion_database_children()` which allows users to copy a list of children (pages) into another database
- correct `Client.append_child_notion_blocks()` (it now copies database children the appended child_databases)

* bulletproof database appension handling

* flake8

* fix replace skipped appension blocks with empty dict

* make changes suggested by Bimba

* flake8
  • Loading branch information
sHermanGriffiths committed Dec 5, 2022
1 parent 5092ed1 commit 1fda6c9
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 32 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,27 @@ Here are some features we're planning to add in the future:

## Changelog

### v0.6.7

- Fix appension bug by replacing skipped child_page and child_database blocks with empty dictionaries in the list returned by `Client.append_child_notion_blocks()`

### v0.6.6

- add `get_children()` method to databases and pages in order to update `Database._children` and `Page._children` manually
- add `Client.copy_notion_database_children()` which allows users to copy a list of children (pages) into another database
- correct `Client.append_child_notion_blocks()` (it now copies database children the appended child_databases)

### v0.6.5

- Fix bug by deleting superfluous print statements

### v0.6.4

- Update how database filters children
- Add version flag

### v0.6.3

- Initiate the n2y.plugins module (somewhere along the line, the `init.py` file must have been deleted).

### v0.6.2
Expand Down
27 changes: 24 additions & 3 deletions n2y/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(self, client, notion_data):
self.archived = notion_data['archived']

self._children = None
self._filtered_children = {}

@property
def filename(self):
Expand All @@ -41,10 +42,30 @@ def children(self):
self._children = self.client.get_database_pages(self.notion_id)
return self._children

def get_children(self):
self._children = self.client.get_database_pages(self.notion_id)

def children_filtered(self, filter, sort=None):
if self._children is None:
self._children = self.client.get_database_pages(self.notion_id, filter, sort)
return self._children
loading_from_cache = filter is not None
if loading_from_cache:
tupled_filter = self._tuplize(filter)
tupled_sort = self._tuplize(sort)
if tupled_filter not in self._filtered_children:
self._filtered_children[tupled_filter] = {}
if tupled_sort not in self._filtered_children[tupled_filter]:
self._filtered_children[tupled_filter][tupled_sort] = \
self.client.get_database_pages(self.notion_id, filter, sort)
return self._filtered_children[tupled_filter][tupled_sort]
else:
return self.children

def _tuplize(self, item):
if callable(getattr(item, "items", None)):
return tuple([(key, self._tuplize(val)) for (key, val) in item.items()])
elif hasattr(item, '__iter__') and type(item) is not str:
return tuple([self._tuplize(i) for i in item])
else:
return (item)

@property
def parent(self):
Expand Down
5 changes: 5 additions & 0 deletions n2y/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys
import logging
import argparse
import pkg_resources

from n2y import notion
from n2y.export import export_page, database_to_yaml, database_to_markdown_files
Expand All @@ -27,6 +28,10 @@ def main(raw_args, access_token):
"--verbosity", '-v', default='INFO',
help="Level to set the root logging module to",
)
parser.add_argument(
"--version", action='version', version=pkg_resources.require("n2y")[0].version,
help="The version of n2y installed",
)

args = parser.parse_args(raw_args)

Expand Down
109 changes: 93 additions & 16 deletions n2y/notion.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,44 @@ def save_file(self, content, page, extension):
temp_file.write(content)
return urljoin(self.media_url, relative_filepath)

def copy_notion_database_children(self, children, destination):
'''
copy the notion children (`children`) of one notion database to another (`destination`)
'''
bad_keys = [
'id',
'url',
'parent',
'created_by',
'created_time',
'last_edited_by',
'last_edited_time',
]
db_children = [
{
key: value
for (key, value) in child.items()
if key not in bad_keys
} for child in children
]
for page in db_children:
page['parent'] = {
'type': 'database_id',
'database_id': destination['id']
}
for key in page['properties'].keys():
del page['properties'][key]['id']
prop_type = page['properties'][key]['type']
del page['properties'][key]['type']
prop_type_info = page['properties'][key][prop_type]
if isinstance(prop_type_info, dict):
del page['properties'][key][prop_type]['id']
elif isinstance(prop_type_info, list) and prop_type != 'relation':
for item in page['properties'][key][prop_type]:
if 'id' in item:
del item['id']
self.create_notion_page(page)

def append_child_notion_blocks(self, block_id, children):
'''
Appends each datapoint of a list of notion_data as children to the block specified by id.
Expand Down Expand Up @@ -409,27 +447,66 @@ def append_blocks(i1, i2, blocks, list):

last_i = 0
children_appended = []
parent = self.get_page_or_database(block_id) or self.get_block(block_id, None)
parent_type = parent.notion_data["object"]
type_is_database = lambda child: 'type' in child and child['type'] == 'child_database'
object_is_database = lambda child: child['object'] == 'database'
type_is_page = lambda child: 'type' in child and child['type'] == 'child_page'
object_is_page = lambda child: child['object'] == 'page'
bad_keys = [
'last_edited_by',
'created_time',
'last_edited_time',
'created_by'
]
for i, child in enumerate(children):
if child['object'] == 'database':
children_appended = append_blocks(last_i, i, children, children_appended)
child_database = self.create_notion_database(child)
children_appended.append(child_database)
last_i = i + 1
elif child['object'] == 'page':
if object_is_database(child) or type_is_database(child):
children_appended = append_blocks(last_i, i, children, children_appended)
child_page = self.create_notion_page(child)
children_appended.append(child_page)
last_i = i + 1
elif child['type'] == 'child_database':
children_appended = append_blocks(last_i, i, children, children_appended)
database = self.get_database(child['id'])
child_database = self.create_notion_database(database.notion_data)
if parent_type == 'block':
logger.warning((
'Skipping database with block type parent as '
'appension is currently unsupported by Notion API'
))
child_database = {}
else:
database = self.get_database(child['id'])
child = {
key: value
for (key, value) in
database.notion_data.items()
if key not in bad_keys
}
child['parent'] = {
'type': f'{parent_type}_id',
f'{parent_type}_id': parent.notion_id
}
child_database = self.create_notion_database(child)
if database.children:
notion_children = [child.notion_data for child in database.children]
self.copy_notion_database_children(notion_children, child_database)
children_appended.append(child_database)
last_i = i + 1
elif child['type'] == 'child_page':
elif object_is_page(child) or type_is_page(child):
children_appended = append_blocks(last_i, i, children, children_appended)
page = self.get_page(child['id'])
child_page = self.create_notion_page(page.notion_data)
if parent_type == 'block':
logger.warning((
'Skipping page with block type parent as '
'appension is currently unsupported by Notion API'
))
child_page = {}
else:
page = self.get_page(child['id'])
child = {
key: value
for (key, value) in
page.notion_data.items()
if key not in bad_keys
}
child['parent'] = {
'type': f'{parent_type}_id',
f'{parent_type}_id': parent.notion_id
}
child_page = self.create_notion_page(child)
children_appended.append(child_page)
last_i = i + 1
elif i == len(children) - 1:
Expand Down
6 changes: 6 additions & 0 deletions n2y/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ def children(self):
self._append_children(block)
return self._children

def get_children(self):
self.block.get_children()
self._children = []
for block in self.block.children:
self._append_children(block)

def _append_children(self, block):
if isinstance(block, ChildPageBlock):
page = self.client.get_page(block.notion_id)
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ universal=1

[flake8]
ignore = E226,E731,E741
exclude = .tox,*.egg,build,data
exclude = .tox,*.egg,build,data,venv
select = E,W,F
max-line-length = 100
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

setup(
name='n2y',
version='0.6.3',
version='0.6.7',
description=description,
long_description=description,
long_description_content_type='text/x-rst',
Expand Down
22 changes: 11 additions & 11 deletions tests/test_append_children.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from n2y.notion import Client
from n2y.notion_mocks import mock_block, mock_database, mock_page, mock_rich_text
from n2y.notion_mocks import mock_block, mock_rich_text
from tests.utils import NOTION_ACCESS_TOKEN


Expand All @@ -25,16 +25,16 @@ def test_append_and_delete_blocks():

def test_append_child_page_or_database():
client = Client(NOTION_ACCESS_TOKEN, plugins=None)
object_id = "c9e17a34da6a4b3295f82a1ad05bc3d8"
page = client.get_page_or_database(object_id)
parent = {'type': 'page_id', 'page_id': page.notion_id}
child_database = mock_database('Child_Database')
child_page = mock_page('Child_Page')
child_database['parent'] = parent
child_page['parent'] = parent
del child_database['url']
del child_page['url']
creation_response = client.append_child_notion_blocks(object_id, [child_database, child_page])
destination_id = "c9e17a34da6a4b3295f82a1ad05bc3d8"
original_id = "0b25a11e78b348c993b4dcf869f25a91"
original = client.get_page_or_database(original_id)
child_database = original.block.children[-1].notion_data
child_page = original.block.children[-2].notion_data
print(child_page)
print(child_database)
creation_response = client.append_child_notion_blocks(
destination_id, [child_database, child_page]
)
assert creation_response
for child in creation_response:
deletion_response = client.delete_notion_block(child)
Expand Down

0 comments on commit 1fda6c9

Please sign in to comment.