mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Finish source-less bytearray initialization after clearing
Preserve option validation and initial export rejection, then avoid a redundant resize guard and storage swap when no source was provided. Keep zero-count callback behavior and all existing regressions. Assisted-by: OpenAI Codex:model identifier unavailable
This commit is contained in:
1 parent
f163e13710
commit
108171daa2
2 files changed
+55
-4
No files matched your search
@@ -23,7 +23,7 @@ use crate::{
|
||||
},
|
||||
},
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
function::{ArgBytesLike, FuncArgs, PyComparisonValue, PySsize},
|
||||
function::{ArgBytesLike, FuncArgs, OptionalArg, PyComparisonValue, PySsize},
|
||||
protocol::{
|
||||
BufferDescriptor, BufferFlags, BufferMethods, BufferResizeGuard, PyBuffer, PyIterReturn,
|
||||
PyMappingMethods, PyNumberMethods, PySequenceMethods,
|
||||
@@ -924,15 +924,17 @@ impl Initializer for PyByteArray {
|
||||
type Args = ByteInnerNewOptions;
|
||||
|
||||
fn init(zelf: &Py<Self>, options: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let source_is_missing = matches!(&options.source, OptionalArg::Missing);
|
||||
// Reject exports and clear existing contents before converting source.
|
||||
zelf.try_resizable(vm)?.elements = Vec::new();
|
||||
// Conversion can call Python, so do not hold the lock across it and
|
||||
// check again for exports acquired by a callback or another thread.
|
||||
let (mut inner, zero_count) =
|
||||
options.get_inner_with_zero_count(bytearray_from_object, vm)?;
|
||||
// A zero integer count performs no further writes, including when its
|
||||
// __index__ callback changed this bytearray or acquired an export.
|
||||
if zero_count {
|
||||
// Missing sources and zero integer counts perform no further writes.
|
||||
// Argument validation above still rejects encoding/errors without a
|
||||
// source; a zero __index__ callback may have changed or exported self.
|
||||
if source_is_missing || zero_count {
|
||||
return Ok(());
|
||||
}
|
||||
core::mem::swap(&mut *zelf.try_resizable(vm)?, &mut inner);
|
||||
|
||||
@@ -1504,3 +1504,52 @@ def test_bytearray_callback_exports():
|
||||
|
||||
|
||||
test_bytearray_callback_exports()
|
||||
|
||||
|
||||
def test_bytearray_missing_source_init():
|
||||
from testutils import assert_raises
|
||||
|
||||
for initial in (b"", b"previous contents"):
|
||||
value = bytearray(initial)
|
||||
assert value.__init__() is None
|
||||
assert value == b""
|
||||
assert value.__alloc__() == 0
|
||||
|
||||
for kwargs, message in (
|
||||
({"encoding": "utf-8"}, "encoding without a string argument"),
|
||||
({"errors": "strict"}, "errors without a string argument"),
|
||||
(
|
||||
{"encoding": "utf-8", "errors": "strict"},
|
||||
"encoding without a string argument",
|
||||
),
|
||||
):
|
||||
value = bytearray(initial)
|
||||
with assert_raises(TypeError) as caught:
|
||||
value.__init__(**kwargs)
|
||||
assert str(caught.exception) == message
|
||||
assert value == b""
|
||||
assert value.__alloc__() == 0
|
||||
|
||||
for kwargs in (
|
||||
{},
|
||||
{"encoding": "utf-8"},
|
||||
{"errors": "strict"},
|
||||
{"encoding": "utf-8", "errors": "strict"},
|
||||
):
|
||||
value = bytearray(initial)
|
||||
with memoryview(value) as view:
|
||||
with assert_raises(BufferError):
|
||||
value.__init__(**kwargs)
|
||||
assert value == initial
|
||||
assert view.tobytes() == initial
|
||||
assert value.__init__() is None
|
||||
assert value == b""
|
||||
|
||||
# Explicit None is a source and must still go through conversion.
|
||||
value = bytearray(initial)
|
||||
with assert_raises(TypeError):
|
||||
value.__init__(None)
|
||||
assert value == b""
|
||||
|
||||
|
||||
test_bytearray_missing_source_init()
|
||||
Reference in new issue
Block a user