Source code for ftrack_api.formatter
# :coding: utf-8
# :copyright: Copyright (c) 2014 ftrack
import os
import sys
from builtins import str
import ftrack_api.entity.base
import ftrack_api.collection
import ftrack_api.symbol
import ftrack_api.inspection
#: Useful filters to pass to :func:`format`.`
FILTER = {
'ignore_unset': (
lambda entity, name, value: value is not ftrack_api.symbol.NOT_SET
)
}
def _can_do_colors():
'''check if we are ( likely ) to be able to handle colors.'''
if "ANSI_COLORS_DISABLED" in os.environ:
return False
if "NO_COLOR" in os.environ:
return False
if "FORCE_COLOR" in os.environ:
return True
return (
hasattr(sys.stdout, "isatty")
and sys.stdout.isatty()
and os.environ.get("TERM") != "dumb"
)
[docs]def format(
entity, formatters=None, attribute_filter=None, recursive=False,
indent=0, indent_first_line=True, _seen=None
):
'''Return formatted string representing *entity*.
*formatters* can be used to customise formatting of elements. It should be a
mapping with one or more of the following keys:
* header - Used to format entity type.
* label - Used to format attribute names.
Specify an *attribute_filter* to control which attributes to include. By
default all attributes are included. The *attribute_filter* should be a
callable that accepts `(entity, attribute_name, attribute_value)` and
returns True if the attribute should be included in the output. For example,
to filter out all unset values::
attribute_filter=ftrack_api.formatter.FILTER['ignore_unset']
If *recursive* is True then recurse into Collections and format each entity
present.
*indent* specifies the overall indentation in spaces of the formatted text,
whilst *indent_first_line* determines whether to apply that indent to the
first generated line.
.. warning::
Iterates over all *entity* attributes which may cause multiple queries
to the server. Turn off auto populating in the session to prevent this.
'''
# Initialise default formatters.
if formatters is None:
formatters = dict()
formatters.setdefault(
'header',
lambda text: '\x1b[1m\x1b[44m\x1b[97m{}\x1b[0m\033[0m'.format(text) if _can_do_colors() else text
)
formatters.setdefault(
'label',
lambda text: '\x1b[1m\x1b[34m{}\x1b[0m\033[0m'.format(text) if _can_do_colors() else text
)
# Determine indents.
spacer = ' ' * indent
if indent_first_line:
first_line_spacer = spacer
else:
first_line_spacer = ''
# Avoid infinite recursion on circular references.
if _seen is None:
_seen = set()
identifier = str(ftrack_api.inspection.identity(entity))
if identifier in _seen:
return (
first_line_spacer +
formatters['header'](entity.entity_type) + '{...}'
)
_seen.add(identifier)
information = list()
information.append(
first_line_spacer + formatters['header'](entity.entity_type)
)
for key, value in sorted(entity.items()):
if attribute_filter is not None:
if not attribute_filter(entity, key, value):
continue
child_indent = indent + len(key) + 3
if isinstance(value, ftrack_api.entity.base.Entity):
value = format(
value,
formatters=formatters,
attribute_filter=attribute_filter,
recursive=recursive,
indent=child_indent,
indent_first_line=False,
_seen=_seen.copy()
)
if isinstance(value, ftrack_api.collection.Collection):
if recursive:
child_values = []
for index, child in enumerate(value):
child_value = format(
child,
formatters=formatters,
attribute_filter=attribute_filter,
recursive=recursive,
indent=child_indent,
indent_first_line=index != 0,
_seen=_seen.copy()
)
child_values.append(child_value)
value = '\n'.join(child_values)
information.append(
spacer + u' {0}: {1}'.format(formatters['label'](key), value)
)
return '\n'.join(information)