diff --git a/IPython/core/display.py b/IPython/core/display.py index 2c9cc01..0915ede 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -164,20 +164,13 @@ def display(*objs, **kwargs): format = InteractiveShell.instance().display_formatter.format for obj in objs: - - # If _ipython_display_ is defined, use that to display this object. - display_method = _safe_get_formatter_method(obj, '_ipython_display_') - if display_method is not None: - try: - display_method(**kwargs) - except NotImplementedError: - pass - else: - continue if raw: publish_display_data(data=obj, metadata=metadata) else: format_dict, md_dict = format(obj, include=include, exclude=exclude) + if not format_dict: + # nothing to display (e.g. _ipython_display_ took over) + continue if metadata: # kwarg-specified metadata gets precedence _merge(md_dict, metadata) diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 544867a..9c1ce82 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -221,20 +221,13 @@ class DisplayHook(Configurable): """ self.check_for_underscore() if result is not None and not self.quiet(): - # If _ipython_display_ is defined, use that to display this object. - display_method = _safe_get_formatter_method(result, '_ipython_display_') - if display_method is not None: - try: - return display_method() - except NotImplementedError: - pass - self.start_displayhook() self.write_output_prompt() format_dict, md_dict = self.compute_format_data(result) - self.write_format_data(format_dict, md_dict) self.update_user_ns(result) - self.log_output(format_dict) + if format_dict: + self.write_format_data(format_dict, md_dict) + self.log_output(format_dict) self.finish_displayhook() def cull_cache(self): diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 6ceb23c..69d5ed3 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -24,6 +24,7 @@ from IPython.core.getipython import get_ipython from IPython.lib import pretty from IPython.utils.traitlets import ( Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List, + Instance, ) from IPython.utils.py3compat import ( unicode_to_str, with_metaclass, PY3, string_types, unicode_type, @@ -89,6 +90,10 @@ class DisplayFormatter(Configurable): else: formatter.enabled = False + self_formatter = Instance(__name__ +'.SelfDisplayingFormatter') + def _self_formatter_default(self): + return SelfDisplayingFormatter(parent=self) + # A dict of formatter whose keys are format types (MIME types) and whose # values are subclasses of BaseFormatter. formatters = Dict() @@ -158,7 +163,11 @@ class DisplayFormatter(Configurable): """ format_dict = {} md_dict = {} - + + if self.self_formatter(obj): + # object handled itself, don't proceed + return {}, {} + for format_type, formatter in self.formatters.items(): if include and format_type not in include: continue @@ -831,6 +840,40 @@ class PDFFormatter(BaseFormatter): _return_type = (bytes, unicode_type) +class SelfDisplayingFormatter(BaseFormatter): + """A Formatter for objects that know how to display themselves. + + To define the callables that compute the representation of your + objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type` + or :meth:`for_type_by_name` methods to register functions that handle + this. Unlike mime-type displays, this method should not return anything, + instead calling any appropriate display methods itself. + + This display formatter has highest priority. + If it fires, no other display formatter will be called. + """ + print_method = ObjectName('_ipython_display_') + _return_type = (type(None), bool) + + + @warn_format_error + def __call__(self, obj): + """Compute the format for an object.""" + if self.enabled: + # lookup registered printer + try: + printer = self.lookup(obj) + except KeyError: + pass + else: + printer(obj) + return True + # Finally look for special method names + method = _safe_get_formatter_method(obj, self.print_method) + if method is not None: + method() + return True + FormatterABC.register(BaseFormatter) FormatterABC.register(PlainTextFormatter) @@ -843,6 +886,7 @@ FormatterABC.register(JPEGFormatter) FormatterABC.register(LatexFormatter) FormatterABC.register(JSONFormatter) FormatterABC.register(JavascriptFormatter) +FormatterABC.register(SelfDisplayingFormatter) def format_display_data(obj, include=None, exclude=None):