title: remove decorator from stack trace
body: <p>I want to write a function decorator that removes itself from the stack trace when an exception occurs (outside the logic specific to the decorator itself), for example when:</p>
  <ul>
  <li>the caller uses arguments that don't match the function signature, or</li>
  <li>the decorated function itself raises an exception.</li>
  </ul>
  <p>Consider the following example:</p>
  <pre class="lang-py prettyprint-override"><code>import functools
  
  def foo(func):
      @functools.wraps(func)
      def wrapper(*args, **kwargs):
          # ... (decorator functionality before calling func)
          result = func(*args, **kwargs)
          # ... (decorator functionality after calling func)
          return result
      return wrapper
  
  @foo
  def f(x):
      return 1 / x
  </code></pre>
  <p>Unfortunately:</p>
  <pre class="lang-py prettyprint-override"><code>&gt;&gt;&gt; f()
  TypeError                                 Traceback (most recent call last)
  Input In [2], in &lt;cell line: 1&gt;()
  ----&gt; 1 f()
  
  Input In [1], in foo.&lt;locals&gt;.wrapper(*args, **kwargs)
        4 @functools.wraps(func)
        5 def wrapper(*args, **kwargs):
        6     # ... (decorator functionality before calling func)
  ----&gt; 7     result = func(*args, **kwargs)
        8     # ... (decorator functionality after calling func)
        9     return result
  
  TypeError: f() missing 1 required positional argument: 'x'
  </code></pre>
  <p>Likewise:</p>
  <pre class="lang-py prettyprint-override"><code>&gt;&gt;&gt; f(0)
  ZeroDivisionError                         Traceback (most recent call last)
  Input In [3], in &lt;cell line: 1&gt;()
  ----&gt; 1 f(0)
  
  Input In [1], in foo.&lt;locals&gt;.wrapper(*args, **kwargs)
        4 @functools.wraps(func)
        5 def wrapper(*args, **kwargs):
        6     # ... (decorator functionality before calling func)
  ----&gt; 7     result = func(*args, **kwargs)
        8     # ... (decorator functionality after calling func)
        9     return result
  
  Input In [1], in f(x)
       12 @foo
       13 def f(x):
  ---&gt; 14     return 1 / x
  
  ZeroDivisionError: division by zero
  </code></pre>
  <p>This leads to &quot;polluted&quot; stack traces that include the decorator code context, file, lineno etc. The problem is compounded when we have nested decorated functions.</p>
  <p>By contrast, observe how e.g. <code>lru_cache</code> keeps the traceback clean:</p>
  <pre class="lang-py prettyprint-override"><code>@functools.lru_cache(maxsize=4)
  def f(x):
      return 1 / x
  
  &gt;&gt;&gt; f()
  TypeError                                 Traceback (most recent call last)
  Input In [5], in &lt;cell line: 1&gt;()
  ----&gt; 1 f()
  
  TypeError: f() missing 1 required positional argument: 'x'
  
  &gt;&gt;&gt; f(0)
  ZeroDivisionError                         Traceback (most recent call last)
  Input In [6], in &lt;cell line: 1&gt;()
  ----&gt; 1 f(0)
  
  Input In [4], in f(x)
        1 @functools.lru_cache(maxsize=4)
        2 def f(x):
  ----&gt; 3     return 1 / x
  
  ZeroDivisionError: division by zero
  </code></pre>
  <p>How to achieve similar cleanliness in custom decorators?</p>