Skip to content

Commit

Permalink
Jinja exc handle (#149)
Browse files Browse the repository at this point in the history
* utilize exc_info saved to Jinja blocks to provide clearer error logs

* test new jinja err logs
  • Loading branch information
sHermanGriffiths authored Sep 12, 2023
1 parent 2edb92f commit 78d099d
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 36 deletions.
84 changes: 51 additions & 33 deletions n2y/plugins/jinjarenderpage.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,44 +322,62 @@ def _get_yaml_from_mentions(self):
url_property=export_defaults["url_property"],
)

def _log_jinja_error(self, err):
message = str(err)
block_ref = f'\nSee the Notion code block here: {self.notion_url}.'
def _specify_err_msg(self, err: Exception):
block_ref: str = f'See the Notion code block here: {self.notion_url}.'
line_num: str = traceback.format_exc().split('>", line ')[1][0]

if self.exc_info is not None:
if type(self.exc_info.err) is KeyError:
if type(self.exc_info.object) is JinjaDatabaseCache:
available_props: str = available_from_list(
list(self.exc_info.object),
'database', 'databases'
)
return f' You attempted to access the "{self.exc_info.args[0]}" database on' + \
f' line {line_num} of said template, but ' + available_props + '. Note ' + \
"that databases must be mentioned in the Notion code block's caption to" + \
' be available and the plugin must have permission to read the database' + \
' via the NOTION_ACCESS_TOKEN. ' + block_ref
elif type(self.exc_info.object) is JinjaDatabaseItem:
available_props: str = available_from_list(
list(self.exc_info.object),
'property', 'properties'
)
return f' You attempted to access the "{self.exc_info.args[0]}" property ' + \
f'of a database item on line {line_num} of said template, but ' + \
available_props + '. ' + block_ref
elif type(self.exc_info.object) is PageProperties:
available_props: str = available_from_list(
list(self.exc_info.object),
'property', 'properties'
)
return f' You attempted to access the "{self.exc_info.args[0]}" property' + \
f' of this page on line {line_num} of said template, but ' + \
available_props + '. ' + block_ref
elif self.exc_info.object in ['test', 'filter']:
return f' Recieved the message "{str(err)}" when evaluating line {line_num}. ' + \
f'The Jinja {self.exc_info.object} "{self.exc_info.method}" raised ' + \
'this error when called with the following argument(s): {\n\t"args": ' + \
f'{self.exc_info.args},\n\t"kwargs": {self.exc_info.kwargs}\n' + '}\n' + \
block_ref
elif type(err) is jinja2.exceptions.TemplateSyntaxError:
return ' There is a syntax error in the Jinja template on line {line_num}.' + \
f' Recieved the message {str(err)}. ' + block_ref

return f' Received the message "{str(err)}" when evaluating line {line_num}. ' + block_ref

def _log_jinja_error(self, err: Exception):
self.error = (
'Error rendering Jinja template on page: ' +
f'{self.page.title.to_plain_text()}.' if self.page else 'Unknown'
'Error rendering a Jinja template on '
f'{self.page.title.to_plain_text()}.' if self.page else 'Unknown Page.'
)

if (db_err := "JinjaDatabaseCache object' has no attribute '") in message:
split_msg = message.split(db_err)
specific_msg = (
f' You attempted to access the "{split_msg[1][:-1]}" database. '
f'{available_from_list(list(self.databases.keys()), "database", "databases")}.'
" Note that databases must be mentioned in the Notion code block's caption to "
'be available. Also, note that the plugin must have permission to read the '
'database via the NOTION_ACCESS_TOKEN'
)
elif (pg_err := "PageProperties object' has no attribute '") in message:
split_msg = message.split(pg_err)
specific_msg = (
f' You attempted to access the "{split_msg[1][:-1]}" page property. '
f'{available_from_list(list(self.page_props.keys()), "property", "properties")}.'
)
else:
specific_msg = None

if specific_msg:
self.error += specific_msg + block_ref
else:
self.error += f' {message}' + block_ref + f'\n{traceback.format_exc()}'
self.error += self._specify_err_msg(err)
logger.error(self.error)

def _render_error(self, err, during_render=True):
jinja_environment = self.client.plugin_data[
'jinjarenderpage'][self.page.notion_id]['environment']
first_pass_output = jinja_environment.globals["first_pass_output"]
only_one_pass = self.render_count == 0 and not first_pass_output.second_pass_is_requested
if during_render and only_one_pass or self.render_count == 1:
first_pass_output = self.jinja_environment.globals["first_pass_output"]
if self.render_count == 1 or during_render and self.render_count == 0 and \
not first_pass_output.second_pass_is_requested:
self._log_jinja_error(err)

def _error_ast(self):
Expand Down
54 changes: 51 additions & 3 deletions tests/test_jinjarenderpage.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ def test_jinja_syntax_err():
page = process_jinja_block(client, caption, jinja_code)
pandoc_ast = page.to_pandoc()
markdown = pandoc_ast_to_markdown(pandoc_ast)
assert 'jinja2.exceptions.TemplateSyntaxError' in markdown
assert 'syntax error' in markdown
assert "Encountered unknown tag 'huhwhat'" in markdown


def test_jinja_render_gfm():
Expand Down Expand Up @@ -174,10 +175,33 @@ def test_jinja_render_with_missing_database():
pandoc_ast = page.to_pandoc()

markdown = pandoc_ast_to_markdown(pandoc_ast)
assert 'You attempted to access the "MISSING" database.' in markdown
assert 'You attempted to access the "MISSING" database' in markdown
assert 'the only available database is "My DB".' in markdown


def test_jinja_render_with_incorrect_db_property():
client = Client('')
database_notion_data = mock_database(title='My DB')
mention_notion_data = mock_database_mention(database_notion_data['id'])
database_pages_notion_data = [mock_page(title='a'), mock_page(title='b')]
caption = [
mock_rich_text(spaced_format_def),
mock_rich_text('My DB', mention=mention_notion_data),
]
jinja_code = "{{ databases[0][0].Foo }}"

with patch.object(Client, "get_notion_database") as mock_get_notion_database:
with patch.object(Client, "get_database_notion_pages") as mock_get_database_notion_pages:
mock_get_notion_database.return_value = database_notion_data
mock_get_database_notion_pages.return_value = database_pages_notion_data
page = process_jinja_block(client, caption, jinja_code)
pandoc_ast = page.to_pandoc()

markdown = pandoc_ast_to_markdown(pandoc_ast)
assert 'You attempted to access the "Foo" property of a database item on line 1' in markdown
assert 'the available properties are "title", "notion_id", and "notion_url".' in markdown


def test_jinja_render_with_missing_page_property():
client = Client('')
database_notion_data = mock_database(title='My DB')
Expand All @@ -197,10 +221,34 @@ def test_jinja_render_with_missing_page_property():
pandoc_ast = page.to_pandoc()

markdown = pandoc_ast_to_markdown(pandoc_ast)
assert 'You attempted to access the "MISSING" page property.' in markdown
assert 'You attempted to access the "MISSING" property' in markdown
assert 'the only available property is "title".' in markdown


def test_jinja_render_with_filter_error():
client = Client('')
database_notion_data = mock_database(title='My DB')
mention_notion_data = mock_database_mention(database_notion_data['id'])
database_pages_notion_data = [mock_page(title='a'), mock_page(title='b')]
caption = [
mock_rich_text(spaced_format_def),
mock_rich_text('My DB', mention=mention_notion_data),
]
jinja_code = "{{ databases[0][0].title|round }}"

with patch.object(Client, "get_notion_database") as mock_get_notion_database:
with patch.object(Client, "get_database_notion_pages") as mock_get_database_notion_pages:
mock_get_notion_database.return_value = database_notion_data
mock_get_database_notion_pages.return_value = database_pages_notion_data
page = process_jinja_block(client, caption, jinja_code)
pandoc_ast = page.to_pandoc()

markdown = pandoc_ast_to_markdown(pandoc_ast)
assert 'Recieved the message "type str doesn\'t define __round__ method"' in markdown
assert 'The Jinja filter "round" raised this error' in markdown
assert 'argument(s): {\n\t"args": (\'a\',),\n\t"kwargs": {}\n}' in markdown


def test_jinja_render_plain():
client = Client('')
caption = mock_rich_text_array('{jinja=plain}')
Expand Down

0 comments on commit 78d099d

Please sign in to comment.