Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update how database filters children and add version flag #89

Merged
merged 14 commits into from
Dec 5, 2022
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
26 changes: 23 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,29 @@ 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
if not filter:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the motivation for these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the database is pulled from the cache and a filter has already been run on it, but you want it to run a different filter it won't. Thus, documents/510k was just giving me the same results as documents/dhf.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add an intermediate variable like loading_from_cache = filter != None or something similar to capture why we're branching?

return self.children
else:
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] = \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: you can avoid the \ by formatting it this way

self._filtered_children[tupled_filter][tupled_sort] = self.client.get_database_pages(
    self.notion_id, filter, sort
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did that for flake8, I tried your suggestion first but it would make the line 101 characters

self.client.get_database_pages(self.notion_id, filter, sort)
return self._filtered_children[tupled_filter][tupled_sort]

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(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd try to pull the version number out of setup.py somehow, so we don't have to update it in two places (we'll probably forget if we have to).

"--version", action='version', version=pkg_resources.require("n2y")[0].version,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yay! thanks for adding this

help="The version of n2y installed",
)

args = parser.parse_args(raw_args)

Expand Down
112 changes: 96 additions & 16 deletions n2y/notion.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,43 @@ 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`)
'''
db_children = [
{
key: value
for (key, value) in child.items()
if key not in [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's extract out this array into a variable at the top or a constant somewhere

'id',
'url',
'parent',
'created_by',
'created_time',
'last_edited_by',
'last_edited_time',
]
} 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 +446,70 @@ 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'
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 [
'last_edited_by',
'created_time',
'last_edited_time',
'created_by'
]
}
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 [
'last_edited_by',
'created_time',
'last_edited_time',
'created_by'
]
}
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