<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Fri, Jan 4, 2019 at 8:18 AM Eric Wieser <<a href="mailto:wieser.eric%2Bnumpy@gmail.com">wieser.eric+numpy@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="m_8257655777652283306markdown-here-wrapper" style="font-size:1em;font-family:Helvetica,arial,freesans,clean,sans-serif;color:rgb(34,34,34);background-color:rgb(255,255,255);border:none;line-height:1.2"><p style="margin:1em 0px"><a href="https://github.com/numpy/numpy/pull/12593" style="color:rgb(51,51,238);text-decoration:none" target="_blank">PR #12593</a> adds a handful of new exception types for . Some consequences of this change are that:</p>
<ol style="padding-left:2em;margin:1em 0px">
<li style="margin:1em 0px">The string formatting is moved to python, allowing us to give better error messages without a lot of work</li>
<li style="margin:1em 0px">The formatting is dispatched lazily, meaning that users trying ufuncs, but catching unsupported loop types don’t have to pay the cost of string formatting</li>
<li style="margin:1em 0px">Users can catch a specific exception type. This might expose more of our internals than we’re willing to though.</li>
<li style="margin:1em 0px">We need to expose these new exception names in the public API.</li></ol></div></div></blockquote><div>Wonderful! This sounds great.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="m_8257655777652283306markdown-here-wrapper" style="font-size:1em;font-family:Helvetica,arial,freesans,clean,sans-serif;color:rgb(34,34,34);background-color:rgb(255,255,255);border:none;line-height:1.2"><ol style="padding-left:2em;margin:1em 0px">
</ol>
<p style="margin:1em 0px">3 & 4 raise some questions, which I’d like some feedback on:</p>
<ul style="padding-left:2em;margin:1em 0px">
<li style="margin:1em 0px"><p style="margin:1em 0px">Should we actually expose the detailed exception types to the user, or should they be kept an implementation detail? One way to hide the implementation details would be</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;overflow:auto;margin:1em 0px"><code class="m_8257655777652283306hljs m_8257655777652283306language-python" style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline;white-space:pre-wrap;border-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,255)"><span class="m_8257655777652283306hljs-class"><span class="m_8257655777652283306hljs-keyword">class</span> <span class="m_8257655777652283306hljs-title">TypeError</span><span class="m_8257655777652283306hljs-params">(builtins.TypeError)</span>:</span>
<span class="m_8257655777652283306hljs-string">"""actually UFuncCastingError"""</span>
_UFuncCastingError = TypeError <span class="m_8257655777652283306hljs-comment"># for internal use when raising</span>
_UFuncCastingError.__module__ = <span class="m_8257655777652283306hljs-keyword">None</span>
<span class="m_8257655777652283306hljs-class"><span class="m_8257655777652283306hljs-keyword">class</span> <span class="m_8257655777652283306hljs-title">TypeError</span><span class="m_8257655777652283306hljs-params">(builtins.TypeError)</span>:</span>
<span class="m_8257655777652283306hljs-string">"""actually UFuncLoopError"""</span>
_UFuncLoopError= TypeError <span class="m_8257655777652283306hljs-comment"># for internal use when raising</span>
_UFuncLoopError .__module__ = <span class="m_8257655777652283306hljs-keyword">None</span>
<span class="m_8257655777652283306hljs-keyword">del</span> TypeError
</code></pre>
<p style="margin:1em 0px">This gives us all the advantages of 1 & 2 without the user noticing that they’re receiving anything other than TypeError, which their tracebacks will continue to show.</p></li></ul></div></div></blockquote><div>I don't think this is a good idea -- think about how much confusion has been caused by how NumPy gives scalars the same repr as Python builtins. It's great to subclass TypeError for our needs, but we shouldn't add more disguised subclasses of builtin Python types.</div><div><br></div><div>If we're really concerned about exposing too much API surface, we should group these errors into logical groups inheriting from NumPy-specific baseclasses, e.g., _UFuncCastingError and _UFuncLoopError could inherit from UFuncError. Then at least users would at least know where to look (at numpy.UFuncError) when their error doesn't serialize properly.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="m_8257655777652283306markdown-here-wrapper" style="font-size:1em;font-family:Helvetica,arial,freesans,clean,sans-serif;color:rgb(34,34,34);background-color:rgb(255,255,255);border:none;line-height:1.2"><ul style="padding-left:2em;margin:1em 0px"><li style="margin:1em 0px">If we do expose them, where should these exceptions go? In the past, we also added <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">AxisError</code><span style="font-size:1em"> and </span><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">TooHardError</code><span style="font-size:1em"> - it would be nice to start being consistent about where to expose these things</span><br></li><li style="margin:1em 0px">
<ol style="padding-left:2em;margin:1em 0px">
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.UFuncCastingError</code> (expands the global namespace even further)</li>
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.core._exceptions.UFuncCastingError</code> (shouldn’t really be private, since users won’t know how to catch it)</li>
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.core.UFuncCastingError</code></li>
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.core.umath.CastingError</code></li>
<li style="margin:1em 0px">A dedicated namespace for exceptions:<ul style="padding-left:2em;margin:1em 0px">
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.errors.UFuncCastingError</code> (matches <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">pandas</code>)</li>
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.exceptions.UFuncCastingError</code></li>
<li style="margin:1em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">np.exc.UFuncCastingError</code> (matches <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:nowrap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline">sqlalchemy</code>)</li></ul></li></ol></li></ul></div></div></blockquote><div>numpy.errors sounds like a good namespace to me. It's short and descriptive. We can put aliases to AxisError and TooHardError in this namespace, too.</div></div></div>