Repository navigation
Conversation
…ameError
These exceptions and their subclasses had no vectorcall, and `__init__`
parsed keywords through PyArg_ParseTupleAndKeywords with a temporary
empty tuple on every call. Error messages are unchanged except when more
keywords than parameters are given, which now names the unexpected
keyword.
The clinic inputs have no docstring, so docstrings are unchanged and
these exceptions don't gain a `__text_signature__`.
pyperf microbenchmark (PGO+LTO, run serially):
| Benchmark | base | vectorcall |
|----------------------------------|:-------:|:---------------------:|
| AttributeError(s, name=s, obj=s) | 127 ns | 41.9 ns: 3.02x faster |
| ImportError(s, name=s, path=s) | 129 ns | 43.4 ns: 2.96x faster |
| NameError(s, name=s) | 88.3 ns | 39.3 ns: 2.24x faster |
| ModuleNotFoundError(s, name=s) | 89.9 ns | 40.6 ns: 2.21x faster |
| AttributeError(s) | 39.4 ns | 32.1 ns: 1.23x faster |
| UnboundLocalError(s) | 38.6 ns | 31.8 ns: 1.22x faster |
| NameError(s) | 38.5 ns | 32.2 ns: 1.19x faster |
| ImportError(s) | 40.7 ns | 34.4 ns: 1.18x faster |
| attribute_error_to_none() | 176 ns | 173 ns: 1.02x faster |
Benchmark code:
```python
import pyperf
runner = pyperf.Runner()
setup = """s = 'x'
class O: pass
o = O()
def attribute_error_to_none():
try:
o.x
except AttributeError:
pass
"""
for stmt in ["AttributeError(s)", "AttributeError(s, name=s, obj=s)",
"NameError(s)", "NameError(s, name=s)",
"ImportError(s)", "ImportError(s, name=s, path=s)",
"ModuleNotFoundError(s, name=s)", "UnboundLocalError(s)",
"attribute_error_to_none()"]:
runner.timeit(stmt, stmt, setup)
```
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$OOO:ImportError", kwlist, | ||
| &name, &path, &name_from)) { | ||
| Py_DECREF(empty_tuple); | ||
| if (BaseException_init((PyObject *)self, args, NULL) == -1) { |
There was a problem hiding this comment.
There is a behavior change for e = ImportError('a'); e.__init__('b', foo=1). The call to e.__init__ fails both on main and the PR, but with the PR e.args is not modified. I think the change is good and no real issue. Maybe not even add a test for or a note in the news entry.
There was a problem hiding this comment.
Yea, I was trying for a while to find a good way to "forward" an args tuple like the original did but it doesn't make a big performance different (< 5 ns) and arguably the new behavior is better.
|
|
||
| def test_varargs15_kw(self): | ||
| msg = r"^ImportError\(\) takes at most 3 keyword arguments \(4 given\)$" | ||
| msg = r"^ImportError\(\) got an unexpected keyword argument 'foo'$" |
There was a problem hiding this comment.
Maybe add a news entry for the change in the error message
There was a problem hiding this comment.
Added a NEWS for the speedup, vectorcall support, and error string change.
These exceptions and their subclasses had no vectorcall, and
__init__parsed keywords through PyArg_ParseTupleAndKeywords with a temporary empty tuple on every call. Error messages are unchanged except when more keywords than parameters are given, which now names the unexpected keyword.The clinic inputs have no docstring, so docstrings are unchanged and these exceptions don't gain a
__text_signature__.pyperf microbenchmark (PGO+LTO, run serially):
Benchmark code: