In CPython's PyErr_NewException[0], the dotted "module.name" passed in is
split on that dot: the content before the dot is set as __module__ in
the created exception class, and the content after it is set as
__name__.
This commit mirrors that behaviour, by introducing a `module` argument
to `PyContext.new_class`: if Some("module_name") is passed, it will be
set as `__module__`. All exception-creating uses of `new_class` are
updated to pass in their module and class names separately.
[0] https://github.com/python/cpython/blob/main/Python/errors.c#L1082-L1087
Without this, the code would accept `b"eggs" % b"ham"` and `b"eggs" %
bytearray(b"ham")` because it would detect bytes and bytearray as
mappings (which _are_ permitted to have leftover, unprocessed
arguments).
Unlike strings, b'%a' and b'%r' are equivalent, and they match the '%a'
behaviour of strings, not '%r'.
Thanks to @youknowone for improving this implementation.
The previous code assumed that, after parsing was complete, both the
padding and the precision integers would always be positive: it
therefore cast them to usize unconditionally. This meant that when a
negative integer was encountered, it would underflow and attempt to
generate a padded string of around usize::MAX, or a float representation
of that precision: unsurprisingly, these fail to allocate.
For simple format strings (e.g. `%-3s`), this works fine: `-` is
detected as a separate token during parsing, so only the positive
integer (3) is passed through.
However, `%*s` expresses "take the first value as the padding integer,
and the second as the string to be padded" (`"%*s" % (-3, ...)` is
analogous to the previous example). In this codepath, the parsing does
not handle the padding integer, so it can't strip the leading `-`: the
padding integer is negative. A negative precision can also be given in
similar fashion, with `"%.*f" % (-3, ...)`.
N.B. This commit does not cause the code to produce the correct _output_
for negative padding integers or precisions provided this way, it
addresses only the crash.
As this extra_test already covered by `test_parameter_chaining` in
`test_genericalias.py`, remove duplicated test
Signed-off-by: snowapril <sinjihng@gmail.com>
In CPython, __str__ and __repr__ for OSError show different results.
This PR try to match this behavior but without the part after the
message (in following example is "'123' -> '456'").
```
In : exc.__repr__()
Out: "FileNotFoundError(2, 'No such file or directory')"
In : exc.__str__()
Out: "[Errno 2] No such file or directory: '123' -> '456'"
In : exc.args
Out: (2, 'No such file or directory')
```