Skip to content

Commit

Permalink
Merge pull request #102 from romanstrazanec/fix_unicode_error
Browse files Browse the repository at this point in the history
Fix Unicode encoding error on non-UTF8 terminals, even when using ASCII mode.

Fixes #95
  • Loading branch information
jonathanj authored Feb 22, 2021
2 parents fa4e612 + dfca2f8 commit f3f152e
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 36 deletions.
47 changes: 24 additions & 23 deletions src/eliottree/_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
from eliottree._theme import get_theme


RIGHT_DOUBLE_ARROW = u'\N{RIGHTWARDS DOUBLE ARROW}'
HOURGLASS = u'\N{WHITE HOURGLASS}'

DEFAULT_IGNORED_KEYS = set([
u'action_status', u'action_type', u'task_level', u'task_uuid',
u'message_type'])
Expand Down Expand Up @@ -51,7 +48,7 @@ def _default_value_formatter(
format.anything(encoding)))


def message_name(theme, format_value, message, end_message=None):
def message_name(theme, format_value, message, end_message=None, options=None):
"""
Derive the name for a message.
Expand All @@ -71,7 +68,7 @@ def message_name(theme, format_value, message, end_message=None):
if end_message:
duration_seconds = end_message.timestamp - message.timestamp
duration = u' {} {}'.format(
HOURGLASS,
options.HOURGLASS,
theme.duration(
format_value(
duration_seconds,
Expand All @@ -87,7 +84,7 @@ def message_name(theme, format_value, message, end_message=None):
return u'{}{} {} {} {}{}'.format(
theme.parent(action_type),
theme.task_level(message.task_level.to_string()),
RIGHT_DOUBLE_ARROW,
options.ARROW,
status_color(message.contents.action_status),
timestamp,
duration)
Expand All @@ -101,7 +98,7 @@ def message_name(theme, format_value, message, end_message=None):
return u'<unnamed>'


def format_node(format_value, theme, node):
def format_node(format_value, theme, options, node):
"""
Format a node for display purposes.
Expand All @@ -120,12 +117,14 @@ def format_node(format_value, theme, node):
theme,
format_value,
node.start_message,
node.end_message)
node.end_message,
options)
elif isinstance(node, WrittenMessage):
return message_name(
theme,
format_value,
node)
node,
options=options)
elif isinstance(node, tuple):
key, value = node
if isinstance(value, (dict, list)):
Expand Down Expand Up @@ -245,6 +244,20 @@ def render_tasks(write, tasks, field_limit=0, ignored_fields=None,
:param bool ascii: Render the tree as plain ASCII instead of Unicode?
:param Theme theme: Theme to use for rendering.
"""
def make_options():
if ascii:
_options = ASCII_OPTIONS
else:
_options = Options()
if colorize_tree:
return ColorizedOptions(
failed_color=theme.tree_failed,
depth_colors=[theme.tree_color0, theme.tree_color1, theme.tree_color2],
options=_options)
return _options

options = make_options()

if ignored_fields is None:
ignored_fields = DEFAULT_IGNORED_KEYS
if colorize is not None:
Expand All @@ -267,25 +280,13 @@ def render_tasks(write, tasks, field_limit=0, ignored_fields=None,
caught_exceptions,
u'<value formatting exception>')
_format_node = track_exceptions(
partial(format_node, _format_value, theme),
partial(format_node, _format_value, theme, options),
caught_exceptions,
u'<node formatting exception>')
_get_children = partial(get_children, ignored_fields)

def make_options():
if ascii:
options = ASCII_OPTIONS
else:
options = Options()
if colorize_tree:
return ColorizedOptions(
failed_color=theme.tree_failed,
depth_colors=[theme.tree_color0, theme.tree_color1, theme.tree_color2],
options=options)
return options

for task in tasks:
write(format_tree(task, _format_node, _get_children, make_options()))
write(format_tree(task, _format_node, _get_children, options))
write(u'\n')

if write_err and caught_exceptions:
Expand Down
24 changes: 13 additions & 11 deletions src/eliottree/test/test_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
render_tasks, tasks_from_iterable)
from eliottree._color import colored
from eliottree._render import (
HOURGLASS, RIGHT_DOUBLE_ARROW, _default_value_formatter, format_node,
_default_value_formatter, format_node,
get_children, message_fields, message_name)
from eliottree.tree_format._text import (
HOURGLASS, RIGHT_DOUBLE_ARROW, Options)
from eliottree._theme import get_theme
from eliottree._util import eliot_ns
from eliottree.test.matchers import ExactlyEquals
Expand Down Expand Up @@ -150,7 +152,7 @@ def test_action_type(self):
"""
message = next(tasks_from_iterable([action_task])).root().start_message
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
StartsWith(colors.parent(message.contents.action_type)))

def test_action_task_level(self):
Expand All @@ -159,7 +161,7 @@ def test_action_task_level(self):
"""
message = next(tasks_from_iterable([action_task])).root().start_message
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
Contains(message.task_level.to_string()))

def test_action_status(self):
Expand All @@ -168,7 +170,7 @@ def test_action_status(self):
"""
message = next(tasks_from_iterable([action_task])).root().start_message
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
Contains(u'started'))

def test_action_status_success(self):
Expand All @@ -179,7 +181,7 @@ def test_action_status_success(self):
action_task, action_task_end,
])).root().end_message
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
Contains(colors.status_success(u'succeeded')))

def test_action_status_failed(self):
Expand All @@ -190,7 +192,7 @@ def test_action_status_failed(self):
action_task, action_task_end_failed,
])).root().end_message
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
Contains(colors.status_failure(u'failed')))

def test_message_type(self):
Expand All @@ -199,7 +201,7 @@ def test_message_type(self):
"""
message = WrittenMessage.from_dict(message_task)
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
StartsWith(colors.parent(message.contents.message_type)))

def test_message_task_level(self):
Expand All @@ -208,7 +210,7 @@ def test_message_task_level(self):
"""
message = WrittenMessage.from_dict(message_task)
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
Contains(message.task_level.to_string()))

def test_unknown(self):
Expand All @@ -217,11 +219,11 @@ def test_unknown(self):
``<unnamed>``.
"""
self.assertThat(
message_name(colors, no_formatting, None),
message_name(colors, no_formatting, None, options=Options()),
ExactlyEquals(u'<unnamed>'))
message = WrittenMessage.from_dict({u'timestamp': 0})
self.assertThat(
message_name(colors, no_formatting, message),
message_name(colors, no_formatting, message, options=Options()),
ExactlyEquals(u'<unnamed>'))


Expand All @@ -233,7 +235,7 @@ def format_node(self, node, format_value=None, colors=no_colors):
if format_value is None:
def format_value(value, field_name=None):
return value
return format_node(format_value, colors, node)
return format_node(format_value, colors, Options(), node)

def test_task(self):
"""
Expand Down
14 changes: 12 additions & 2 deletions src/eliottree/tree_format/_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@
import itertools


RIGHT_DOUBLE_ARROW = u'\N{RIGHTWARDS DOUBLE ARROW}'
HOURGLASS = u'\N{WHITE HOURGLASS}'


class Options(object):
def __init__(self,
FORK=u'\u251c',
LAST=u'\u2514',
VERTICAL=u'\u2502',
HORIZONTAL=u'\u2500',
NEWLINE=u'\u23ce'):
NEWLINE=u'\u23ce',
ARROW=RIGHT_DOUBLE_ARROW,
HOURGLASS=HOURGLASS):
self.FORK = FORK
self.LAST = LAST
self.VERTICAL = VERTICAL
self.HORIZONTAL = HORIZONTAL
self.NEWLINE = NEWLINE
self.ARROW = ARROW
self.HOURGLASS = HOURGLASS

def color(self, node, depth):
return lambda text, *a, **kw: text
Expand All @@ -51,7 +59,9 @@ def last(self):
LAST=u'+',
VERTICAL=u'|',
HORIZONTAL=u'-',
NEWLINE=u'\n')
NEWLINE=u'\n',
ARROW=u'=>',
HOURGLASS='|Y|')


def _format_newlines(prefix, formatted_node, options):
Expand Down

0 comments on commit f3f152e

Please sign in to comment.