title: Implications of the IPython "Canary Method" and what happens if it exists?
body: <p>The IPython source code includes <a href="https://github.com/ipython/ipython/blob/76481531fde0545439cfc3e86febdefd47aa5a43/IPython/utils/dir2.py#L65" rel="noreferrer">a <code>getattr</code> check</a> that tests for the existence of <code>'_ipython_canary_method_should_not_exist_'</code> at the beginning of the <code>get_real_method</code> function:</p>
  
  <pre><code>def get_real_method(obj, name):
      """Like getattr, but with a few extra sanity checks:
      - If obj is a class, ignore everything except class methods
      - Check if obj is a proxy that claims to have all attributes
      - Catch attribute access failing with any exception
      - Check that the attribute is a callable object
      Returns the method or None.
      """
      try:
          canary = getattr(obj, '_ipython_canary_method_should_not_exist_', None)
      except Exception:
          return None
  
      if canary is not None:
          # It claimed to have an attribute it should never have
          return None
  </code></pre>
  
  <p>And although it's easy enough to <a href="https://duckduckgo.com/?q=%22_ipython_canary_method_should_not_exist_%22+site%3Agithub.com+&amp;t=ffsb&amp;ia=web" rel="noreferrer">find</a> other coders special-casing this name, it's a harder to find any meaningful explanation of why.</p>
  
  <p>Given these two classes:</p>
  
  <pre><code>from __future__ import print_function
  
  class Parrot(object):
      def __getattr__(self, attr):
          print(attr)
          return lambda *a, **kw: print(attr, a, kw)
  
  class DeadParrot(object):
      def __getattr__(self, attr):
          print(attr)
          if attr == '_ipython_canary_method_should_not_exist_':
              raise AttributeError(attr)
          return lambda *a, **kw: print(attr, a, kw)
  </code></pre>
  
  <p>It seems that IPython is using the existence or lack of this method to decide whether to use <code>repr</code> or one of its <a href="https://ipython.readthedocs.io/en/stable/config/integrating.html#rich-display" rel="noreferrer">rich display methods</a>. Intentionally thwarting the test in <code>DeadParrot</code> causes IPython to look up and invoke <code>_repr_mimebundle_</code>.</p>
  
  <p>I'm writing an object that pretends all attrs exist. How do I decide whether to special-case this?</p>