mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Clippy warn on unnecessary wraps (#7869)
This commit is contained in:
1 parent
f8e0eeb579
commit
e8711edd2d
72 files changed
+625
-650
No files matched your search
@@ -358,3 +358,4 @@ inconsistent_struct_constructor = "warn"
|
||||
manual_is_variant_and = "warn"
|
||||
map_unwrap_or = "warn"
|
||||
must_use_candidate = "warn"
|
||||
unnecessary_wraps = "warn"
|
||||
@@ -1231,37 +1231,37 @@ impl Compiler {
|
||||
|
||||
/// Get the cell-relative index of a free variable.
|
||||
/// Returns ncells + freevar_idx. Fixed up to localsplus index during finalize.
|
||||
fn get_free_var_index(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
|
||||
fn get_free_var_index(&mut self, name: &str) -> oparg::VarNum {
|
||||
let info = self.code_stack.last_mut().unwrap();
|
||||
let idx = info
|
||||
.metadata
|
||||
.freevars
|
||||
.get_index_of(name)
|
||||
.unwrap_or_else(|| info.metadata.freevars.insert_full(name.to_owned()).0);
|
||||
Ok((idx + info.metadata.cellvars.len()).to_u32().into())
|
||||
(idx + info.metadata.cellvars.len()).to_u32().into()
|
||||
}
|
||||
|
||||
/// Get the cell-relative index of a cell variable.
|
||||
/// Returns cellvar_idx. Fixed up to localsplus index during finalize.
|
||||
fn get_cell_var_index(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
|
||||
fn get_cell_var_index(&mut self, name: &str) -> oparg::VarNum {
|
||||
let info = self.code_stack.last_mut().unwrap();
|
||||
let idx = info
|
||||
.metadata
|
||||
.cellvars
|
||||
.get_index_of(name)
|
||||
.unwrap_or_else(|| info.metadata.cellvars.insert_full(name.to_owned()).0);
|
||||
Ok(idx.to_u32().into())
|
||||
idx.to_u32().into()
|
||||
}
|
||||
|
||||
/// Get the index of a local variable.
|
||||
fn get_local_var_index(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
|
||||
fn get_local_var_index(&mut self, name: &str) -> oparg::VarNum {
|
||||
let info = self.code_stack.last_mut().unwrap();
|
||||
let idx = info
|
||||
.metadata
|
||||
.varnames
|
||||
.get_index_of(name)
|
||||
.unwrap_or_else(|| info.metadata.varnames.insert_full(name.to_owned()).0);
|
||||
Ok(idx.to_u32().into())
|
||||
idx.to_u32().into()
|
||||
}
|
||||
|
||||
/// Get the index of a global name.
|
||||
@@ -1479,8 +1479,8 @@ impl Compiler {
|
||||
// Load __class__ from cell/free variable
|
||||
let scope = self.get_ref_type("__class__").map_err(|e| self.error(e))?;
|
||||
let idx = match scope {
|
||||
SymbolScope::Cell => self.get_cell_var_index("__class__")?,
|
||||
SymbolScope::Free => self.get_free_var_index("__class__")?,
|
||||
SymbolScope::Cell => self.get_cell_var_index("__class__"),
|
||||
SymbolScope::Free => self.get_free_var_index("__class__"),
|
||||
_ => {
|
||||
return Err(self.error(CodegenErrorType::SyntaxError(
|
||||
"super(): __class__ cell not found".to_owned(),
|
||||
@@ -1929,14 +1929,14 @@ impl Compiler {
|
||||
|
||||
// Emit format validation: if format > VALUE_WITH_FAKE_GLOBALS: raise NotImplementedError
|
||||
// VALUE_WITH_FAKE_GLOBALS = 2 (from annotationlib.Format)
|
||||
self.emit_format_validation()?;
|
||||
self.emit_format_validation();
|
||||
|
||||
Ok(Some(saved_ctx))
|
||||
}
|
||||
|
||||
/// Emit format parameter validation for annotation scope
|
||||
/// if format > VALUE_WITH_FAKE_GLOBALS (2): raise NotImplementedError
|
||||
fn emit_format_validation(&mut self) -> CompileResult<()> {
|
||||
fn emit_format_validation(&mut self) {
|
||||
// Load format parameter (first local variable, index 0)
|
||||
emit!(
|
||||
self,
|
||||
@@ -1976,8 +1976,6 @@ impl Compiler {
|
||||
|
||||
// Body label - continue with annotation evaluation
|
||||
self.switch_to_block(body_block);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Push a new fblock
|
||||
@@ -2228,11 +2226,9 @@ impl Compiler {
|
||||
self._name_inner(name, |i| &mut i.metadata.names)
|
||||
}
|
||||
|
||||
fn varname(&mut self, name: &str) -> CompileResult<oparg::VarNum> {
|
||||
// Note: __debug__ checks are now handled in symboltable phase
|
||||
Ok(oparg::VarNum::from_u32(
|
||||
self._name_inner(name, |i| &mut i.metadata.varnames),
|
||||
))
|
||||
fn varname(&mut self, name: &str) -> oparg::VarNum {
|
||||
// NOTE: __debug__ checks are now handled in symboltable phase
|
||||
oparg::VarNum::from_u32(self._name_inner(name, |i| &mut i.metadata.varnames))
|
||||
}
|
||||
|
||||
fn _name_inner(
|
||||
@@ -2784,8 +2780,8 @@ impl Compiler {
|
||||
match op_type {
|
||||
NameOp::Deref => {
|
||||
let i = match actual_scope {
|
||||
SymbolScope::Free => self.get_free_var_index(&name)?,
|
||||
SymbolScope::Cell => self.get_cell_var_index(&name)?,
|
||||
SymbolScope::Free => self.get_free_var_index(&name),
|
||||
SymbolScope::Cell => self.get_cell_var_index(&name),
|
||||
_ => unreachable!("Invalid scope for Deref operation"),
|
||||
};
|
||||
|
||||
@@ -2800,7 +2796,7 @@ impl Compiler {
|
||||
emit!(self, Instruction::LoadFromDictOrDeref { i });
|
||||
// can_see_class_scope: LOAD_DEREF(__classdict__) first
|
||||
} else if can_see_class_scope {
|
||||
let classdict_idx = self.get_free_var_index("__classdict__")?;
|
||||
let classdict_idx = self.get_free_var_index("__classdict__");
|
||||
emit!(self, Instruction::LoadDeref { i: classdict_idx });
|
||||
emit!(self, Instruction::LoadFromDictOrDeref { i });
|
||||
} else {
|
||||
@@ -2812,7 +2808,7 @@ impl Compiler {
|
||||
};
|
||||
}
|
||||
NameOp::Fast => {
|
||||
let var_num = self.get_local_var_index(&name)?;
|
||||
let var_num = self.get_local_var_index(&name);
|
||||
match usage {
|
||||
NameUsage::Load => emit!(self, Instruction::LoadFast { var_num }),
|
||||
NameUsage::Store => emit!(self, Instruction::StoreFast { var_num }),
|
||||
@@ -2852,7 +2848,7 @@ impl Compiler {
|
||||
match usage {
|
||||
NameUsage::Load => {
|
||||
// Load __classdict__ first (it's a free variable in annotation scope)
|
||||
let classdict_idx = self.get_free_var_index("__classdict__")?;
|
||||
let classdict_idx = self.get_free_var_index("__classdict__");
|
||||
emit!(self, Instruction::LoadDeref { i: classdict_idx });
|
||||
emit!(self, Instruction::LoadFromDictOrGlobals { i: idx });
|
||||
}
|
||||
@@ -3414,16 +3410,16 @@ impl Compiler {
|
||||
.chain(kw_without_defaults)
|
||||
.chain(kw_with_defaults.into_iter().map(|(arg, _)| arg));
|
||||
for name in args_iter {
|
||||
self.varname(name.name.as_str())?;
|
||||
self.varname(name.name.as_str());
|
||||
}
|
||||
|
||||
if let Some(name) = parameters.vararg.as_deref() {
|
||||
self.current_code_info().flags |= bytecode::CodeFlags::VARARGS;
|
||||
self.varname(name.name.as_str())?;
|
||||
self.varname(name.name.as_str());
|
||||
}
|
||||
if let Some(name) = parameters.kwarg.as_deref() {
|
||||
self.current_code_info().flags |= bytecode::CodeFlags::VARKEYWORDS;
|
||||
self.varname(name.name.as_str())?;
|
||||
self.varname(name.name.as_str());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -3472,7 +3468,7 @@ impl Compiler {
|
||||
.varnames
|
||||
.insert(".format".to_owned());
|
||||
|
||||
self.emit_format_validation()?;
|
||||
self.emit_format_validation();
|
||||
|
||||
// TypeParams scope is function-like
|
||||
let prev_ctx = self.ctx;
|
||||
@@ -3525,7 +3521,7 @@ impl Compiler {
|
||||
.metadata
|
||||
.varnames
|
||||
.insert(".format".to_owned());
|
||||
self.emit_format_validation()?;
|
||||
self.emit_format_validation();
|
||||
|
||||
let prev_ctx = self.ctx;
|
||||
self.ctx = CompileContext {
|
||||
@@ -5108,7 +5104,7 @@ impl Compiler {
|
||||
.insert("format".to_owned());
|
||||
|
||||
// Emit format validation: if format > VALUE_WITH_FAKE_GLOBALS: raise NotImplementedError
|
||||
self.emit_format_validation()?;
|
||||
self.emit_format_validation();
|
||||
|
||||
emit!(self, Instruction::BuildMap { count: 0 });
|
||||
|
||||
@@ -5147,7 +5143,7 @@ impl Compiler {
|
||||
value: simple_idx.into(),
|
||||
});
|
||||
if parent_scope_type == CompilerScope::Class {
|
||||
let idx = self.get_free_var_index("__conditional_annotations__")?;
|
||||
let idx = self.get_free_var_index("__conditional_annotations__");
|
||||
emit!(self, Instruction::LoadDeref { i: idx });
|
||||
} else {
|
||||
let cond_annotations_name = self.name("__conditional_annotations__");
|
||||
@@ -5681,7 +5677,7 @@ impl Compiler {
|
||||
// setup so nested generic classes match CPython's prologue order.
|
||||
if self.current_symbol_table().needs_classdict {
|
||||
emit!(self, Instruction::LoadLocals);
|
||||
let classdict_idx = self.get_cell_var_index("__classdict__")?;
|
||||
let classdict_idx = self.get_cell_var_index("__classdict__");
|
||||
emit!(self, Instruction::StoreDeref { i: classdict_idx });
|
||||
}
|
||||
|
||||
@@ -5751,7 +5747,7 @@ impl Compiler {
|
||||
|
||||
// Store __classdictcell__ if __classdict__ is a cell variable
|
||||
if self.current_symbol_table().needs_classdict {
|
||||
let classdict_idx = u32::from(self.get_cell_var_index("__classdict__")?);
|
||||
let classdict_idx = u32::from(self.get_cell_var_index("__classdict__"));
|
||||
emit!(self, PseudoInstruction::LoadClosure { i: classdict_idx });
|
||||
self.set_no_location();
|
||||
let classdictcell = self.name("__classdictcell__");
|
||||
@@ -6596,24 +6592,23 @@ impl Compiler {
|
||||
|
||||
/// Ensures that `pc.fail_pop` has at least `n + 1` entries.
|
||||
/// If not, new labels are generated and pushed until the required size is reached.
|
||||
fn ensure_fail_pop(&mut self, pc: &mut PatternContext, n: usize) -> CompileResult<()> {
|
||||
fn ensure_fail_pop(&mut self, pc: &mut PatternContext, n: usize) {
|
||||
let required_size = n + 1;
|
||||
if required_size <= pc.fail_pop.len() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
while pc.fail_pop.len() < required_size {
|
||||
let new_block = self.new_block();
|
||||
pc.fail_pop.push(new_block);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn jump_to_fail_pop(&mut self, pc: &mut PatternContext, op: JumpOp) -> CompileResult<()> {
|
||||
fn jump_to_fail_pop(&mut self, pc: &mut PatternContext, op: JumpOp) {
|
||||
// Compute the total number of items to pop:
|
||||
// items on top plus the captured objects.
|
||||
let pops = pc.on_top + pc.stores.len();
|
||||
// Ensure that the fail_pop vector has at least `pops + 1` elements.
|
||||
self.ensure_fail_pop(pc, pops)?;
|
||||
self.ensure_fail_pop(pc, pops);
|
||||
// Emit a jump using the jump target stored at index `pops`.
|
||||
match op {
|
||||
JumpOp::Jump => {
|
||||
@@ -6622,7 +6617,7 @@ impl Compiler {
|
||||
PseudoInstruction::Jump {
|
||||
delta: pc.fail_pop[pops]
|
||||
}
|
||||
);
|
||||
)
|
||||
}
|
||||
JumpOp::PopJumpIfFalse => {
|
||||
emit!(
|
||||
@@ -6630,19 +6625,18 @@ impl Compiler {
|
||||
Instruction::PopJumpIfFalse {
|
||||
delta: pc.fail_pop[pops]
|
||||
}
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
|
||||
/// Emits the necessary POP instructions for all failure targets in the pattern context,
|
||||
/// then resets the fail_pop vector.
|
||||
fn emit_and_reset_fail_pop(&mut self, pc: &mut PatternContext) -> CompileResult<()> {
|
||||
fn emit_and_reset_fail_pop(&mut self, pc: &mut PatternContext) {
|
||||
// If the fail_pop vector is empty, nothing needs to be done.
|
||||
if pc.fail_pop.is_empty() {
|
||||
debug_assert!(pc.fail_pop.is_empty());
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
// Iterate over the fail_pop vector in reverse order, skipping the first label.
|
||||
for &label in pc.fail_pop.iter().skip(1).rev() {
|
||||
@@ -6655,11 +6649,10 @@ impl Compiler {
|
||||
pc.fail_pop.clear();
|
||||
// Free the memory used by the vector.
|
||||
pc.fail_pop.shrink_to_fit();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Duplicate the effect of Python 3.10's ROT_* instructions using SWAPs.
|
||||
fn pattern_helper_rotate(&mut self, mut count: usize) -> CompileResult<()> {
|
||||
fn pattern_helper_rotate(&mut self, mut count: usize) {
|
||||
// Rotate TOS (top of stack) to position `count` down
|
||||
// This is done by a series of swaps
|
||||
// For count=1, no rotation needed (already at top)
|
||||
@@ -6675,7 +6668,6 @@ impl Compiler {
|
||||
);
|
||||
count -= 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper to store a captured name for a star pattern.
|
||||
@@ -6711,7 +6703,7 @@ impl Compiler {
|
||||
|
||||
// Calculate how many items to rotate:
|
||||
let rotations = pc.on_top + pc.stores.len() + 1;
|
||||
self.pattern_helper_rotate(rotations)?;
|
||||
self.pattern_helper_rotate(rotations);
|
||||
|
||||
// Append the name to the captured stores.
|
||||
pc.stores.push(name.to_string());
|
||||
@@ -6993,7 +6985,7 @@ impl Compiler {
|
||||
|
||||
// At this point the TOS is a tuple of (nargs + n_attrs) attributes (or None).
|
||||
pc.on_top += 1;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
|
||||
// Unpack the tuple into (nargs + n_attrs) items.
|
||||
let total = nargs + n_attrs;
|
||||
@@ -7065,7 +7057,7 @@ impl Compiler {
|
||||
emit!(self, Instruction::MatchMapping);
|
||||
// Stack: [subject, is_mapping]
|
||||
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
// Stack: [subject]
|
||||
|
||||
// Special case: empty pattern {} with no rest
|
||||
@@ -7088,7 +7080,7 @@ impl Compiler {
|
||||
opname: ComparisonOperator::GreaterOrEqual
|
||||
}
|
||||
);
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
// Stack: [subject]
|
||||
}
|
||||
|
||||
@@ -7163,7 +7155,7 @@ impl Compiler {
|
||||
);
|
||||
|
||||
// Stack: [subject, keys_tuple, values_tuple, bool]
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
// Stack: [subject, keys_tuple, values_tuple]
|
||||
|
||||
// Unpack values (the original values_tuple)
|
||||
@@ -7302,7 +7294,7 @@ impl Compiler {
|
||||
// Also perform the same rotation on the evaluation stack.
|
||||
self.set_source_range(alt.range());
|
||||
for _ in 0..=i_stores {
|
||||
self.pattern_helper_rotate(i_control + 1)?;
|
||||
self.pattern_helper_rotate(i_control + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7312,7 +7304,7 @@ impl Compiler {
|
||||
self.set_source_range(alt.range());
|
||||
emit!(self, PseudoInstruction::Jump { delta: end });
|
||||
self.set_source_range(alt.range());
|
||||
self.emit_and_reset_fail_pop(pc)?;
|
||||
self.emit_and_reset_fail_pop(pc);
|
||||
}
|
||||
|
||||
// Restore the original pattern context.
|
||||
@@ -7325,7 +7317,7 @@ impl Compiler {
|
||||
// No alternative matched: pop the subject and fail.
|
||||
self.set_source_range(p.range());
|
||||
emit!(self, Instruction::PopTop);
|
||||
self.jump_to_fail_pop(pc, JumpOp::Jump)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::Jump);
|
||||
|
||||
// Use the label "end".
|
||||
self.switch_to_block(end);
|
||||
@@ -7336,7 +7328,7 @@ impl Compiler {
|
||||
for i in 0..n_stores {
|
||||
// Rotate the capture to its proper place.
|
||||
self.set_source_range(p.range());
|
||||
self.pattern_helper_rotate(n_rots)?;
|
||||
self.pattern_helper_rotate(n_rots);
|
||||
let name = &control.as_ref().unwrap()[i];
|
||||
// Check for duplicate binding.
|
||||
if pc.stores.contains(name) {
|
||||
@@ -7384,7 +7376,7 @@ impl Compiler {
|
||||
// Keep the subject on top during the sequence and length checks.
|
||||
pc.on_top += 1;
|
||||
emit!(self, Instruction::MatchSequence);
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
|
||||
if star.is_none() {
|
||||
// No star: len(subject) == size
|
||||
@@ -7396,7 +7388,7 @@ impl Compiler {
|
||||
opname: ComparisonOperator::Equal
|
||||
}
|
||||
);
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
} else if size > 1 {
|
||||
// Star exists: len(subject) >= size - 1
|
||||
emit!(self, Instruction::GetLen);
|
||||
@@ -7409,7 +7401,7 @@ impl Compiler {
|
||||
opname: ComparisonOperator::GreaterOrEqual
|
||||
}
|
||||
);
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
}
|
||||
|
||||
// Whatever comes next should consume the subject.
|
||||
@@ -7441,7 +7433,7 @@ impl Compiler {
|
||||
}
|
||||
);
|
||||
emit!(self, Instruction::ToBool);
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -7449,7 +7441,7 @@ impl Compiler {
|
||||
&mut self,
|
||||
p: &ast::PatternMatchSingleton,
|
||||
pc: &mut PatternContext,
|
||||
) -> CompileResult<()> {
|
||||
) {
|
||||
// Load the singleton constant value.
|
||||
self.emit_load_const(match p.value {
|
||||
ast::Singleton::None => ConstantData::None,
|
||||
@@ -7459,8 +7451,7 @@ impl Compiler {
|
||||
// Compare using the "Is" operator.
|
||||
emit!(self, Instruction::IsOp { invert: Invert::No });
|
||||
// Jump to the failure label if the comparison is false.
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse)?;
|
||||
Ok(())
|
||||
self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
|
||||
}
|
||||
|
||||
fn compile_pattern(
|
||||
@@ -7475,7 +7466,8 @@ impl Compiler {
|
||||
self.compile_pattern_value(pattern_type, pattern_context)
|
||||
}
|
||||
ast::Pattern::MatchSingleton(pattern_type) => {
|
||||
self.compile_pattern_singleton(pattern_type, pattern_context)
|
||||
self.compile_pattern_singleton(pattern_type, pattern_context);
|
||||
Ok(())
|
||||
}
|
||||
ast::Pattern::MatchSequence(pattern_type) => {
|
||||
self.compile_pattern_sequence(pattern_type, pattern_context)
|
||||
@@ -7544,7 +7536,7 @@ impl Compiler {
|
||||
}
|
||||
|
||||
if let Some(ref guard) = m.guard {
|
||||
self.ensure_fail_pop(pattern_context, 0)?;
|
||||
self.ensure_fail_pop(pattern_context, 0);
|
||||
self.compile_jump_if_inner(
|
||||
guard,
|
||||
false,
|
||||
@@ -7573,7 +7565,7 @@ impl Compiler {
|
||||
last.match_success_jump = true;
|
||||
}
|
||||
self.set_source_range(m.pattern.range());
|
||||
self.emit_and_reset_fail_pop(pattern_context)?;
|
||||
self.emit_and_reset_fail_pop(pattern_context);
|
||||
}
|
||||
|
||||
if has_default {
|
||||
@@ -9834,7 +9826,7 @@ impl Compiler {
|
||||
// Set qualname for comprehension
|
||||
self.set_qualname();
|
||||
|
||||
let arg0 = self.varname(".0")?;
|
||||
let arg0 = self.varname(".0");
|
||||
|
||||
let return_none = init_collection.is_none();
|
||||
|
||||
@@ -10184,7 +10176,7 @@ impl Compiler {
|
||||
self.set_source_range(comprehension_range);
|
||||
let mut total_stack_items: usize = 0;
|
||||
for name in &pushed_locals {
|
||||
let var_num = self.varname(name)?;
|
||||
let var_num = self.varname(name);
|
||||
emit!(self, Instruction::LoadFastAndClear { var_num });
|
||||
total_stack_items += 1;
|
||||
// If the comp symbol is CELL, emit MAKE_CELL to create fresh cell
|
||||
@@ -10197,9 +10189,9 @@ impl Compiler {
|
||||
.get(name)
|
||||
.is_some_and(|s| s.scope == SymbolScope::Free)
|
||||
{
|
||||
self.get_free_var_index(name)?
|
||||
self.get_free_var_index(name)
|
||||
} else {
|
||||
self.get_cell_var_index(name)?
|
||||
self.get_cell_var_index(name)
|
||||
};
|
||||
emit!(self, Instruction::MakeCell { i });
|
||||
}
|
||||
@@ -10375,7 +10367,7 @@ impl Compiler {
|
||||
}
|
||||
);
|
||||
for name in pushed_locals.iter().rev() {
|
||||
let var_num = self.varname(name)?.as_u32();
|
||||
let var_num = self.varname(name).as_u32();
|
||||
emit!(self, PseudoInstruction::StoreFastMaybeNull { var_num });
|
||||
}
|
||||
// Re-raise the exception
|
||||
@@ -10397,7 +10389,7 @@ impl Compiler {
|
||||
|
||||
// Restore saved locals (StoreFast restores the saved cell object for merged cells)
|
||||
for name in pushed_locals.iter().rev() {
|
||||
let var_num = self.varname(name)?.as_u32();
|
||||
let var_num = self.varname(name).as_u32();
|
||||
emit!(self, PseudoInstruction::StoreFastMaybeNull { var_num });
|
||||
}
|
||||
self.set_source_range(saved_source_range);
|
||||
@@ -11481,7 +11473,8 @@ impl Compiler {
|
||||
)?;
|
||||
}
|
||||
self.set_source_range(fstring_range);
|
||||
self.finish_fstring(pending_literal, pending_literal_no_location, element_count)
|
||||
self.finish_fstring(pending_literal, pending_literal_no_location, element_count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_fstring_parts_joined(&mut self, fstring: &[ast::FStringPart]) -> CompileResult<()> {
|
||||
@@ -11545,7 +11538,7 @@ impl Compiler {
|
||||
mut pending_literal: Option<Wtf8Buf>,
|
||||
mut pending_literal_no_location: bool,
|
||||
mut element_count: u32,
|
||||
) -> CompileResult<()> {
|
||||
) {
|
||||
let keep_empty = element_count == 0;
|
||||
self.emit_pending_fstring_literal(
|
||||
&mut pending_literal,
|
||||
@@ -11567,8 +11560,6 @@ impl Compiler {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish_fstring_join(
|
||||
@@ -11690,7 +11681,8 @@ impl Compiler {
|
||||
&mut element_count,
|
||||
false,
|
||||
)?;
|
||||
self.finish_fstring(pending_literal, pending_literal_no_location, element_count)
|
||||
self.finish_fstring(pending_literal, pending_literal_no_location, element_count);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_fstring_elements_joined(
|
||||
|
||||
@@ -68,7 +68,7 @@ impl StringParser {
|
||||
self.source[self.cursor..].as_bytes().first().copied()
|
||||
}
|
||||
|
||||
fn parse_unicode_literal(&mut self, literal_number: usize) -> Result<CodePoint, LexicalError> {
|
||||
fn parse_unicode_literal(&mut self, literal_number: usize) -> CodePoint {
|
||||
let mut p: u32 = 0u32;
|
||||
for i in 1..=literal_number {
|
||||
match self.next_char() {
|
||||
@@ -79,7 +79,7 @@ impl StringParser {
|
||||
None => unreachable!(),
|
||||
}
|
||||
}
|
||||
Ok(CodePoint::from_u32(p).unwrap())
|
||||
CodePoint::from_u32(p).unwrap()
|
||||
}
|
||||
|
||||
fn parse_octet(&mut self, o: u8) -> char {
|
||||
@@ -134,9 +134,9 @@ impl StringParser {
|
||||
't' => '\t'.into(),
|
||||
'v' => '\x0b'.into(),
|
||||
o @ '0'..='7' => self.parse_octet(o as u8).into(),
|
||||
'x' => self.parse_unicode_literal(2)?,
|
||||
'u' if !self.flags.is_byte_string() => self.parse_unicode_literal(4)?,
|
||||
'U' if !self.flags.is_byte_string() => self.parse_unicode_literal(8)?,
|
||||
'x' => self.parse_unicode_literal(2),
|
||||
'u' if !self.flags.is_byte_string() => self.parse_unicode_literal(4),
|
||||
'U' if !self.flags.is_byte_string() => self.parse_unicode_literal(8),
|
||||
'N' if !self.flags.is_byte_string() => self.parse_unicode_name()?.into(),
|
||||
// Special cases where the escape sequence is not a single character
|
||||
'\n' => return Ok(None),
|
||||
|
||||
+33
-11
@@ -580,7 +580,13 @@ impl FormatSpec {
|
||||
},
|
||||
};
|
||||
|
||||
self.format_sign_and_align(&AsciiStr::new(&magnitude_str), sign_str, FormatAlign::Right)
|
||||
Ok(
|
||||
self.format_sign_and_align(
|
||||
&AsciiStr::new(&magnitude_str),
|
||||
sign_str,
|
||||
FormatAlign::Right,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Format a float with locale-aware 'n' format.
|
||||
@@ -620,7 +626,13 @@ impl FormatSpec {
|
||||
}
|
||||
};
|
||||
|
||||
self.format_sign_and_align(&AsciiStr::new(&magnitude_str), sign_str, FormatAlign::Right)
|
||||
Ok(
|
||||
self.format_sign_and_align(
|
||||
&AsciiStr::new(&magnitude_str),
|
||||
sign_str,
|
||||
FormatAlign::Right,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Format a complex number with locale-aware 'n' format.
|
||||
@@ -672,7 +684,7 @@ impl FormatSpec {
|
||||
// No parentheses for 'n' format (CPython: add_parens=0)
|
||||
let magnitude_str = format!("{grouped_re}{grouped_im}");
|
||||
|
||||
self.format_sign_and_align(&AsciiStr::new(&magnitude_str), "", FormatAlign::Right)
|
||||
Ok(self.format_sign_and_align(&AsciiStr::new(&magnitude_str), "", FormatAlign::Right))
|
||||
}
|
||||
|
||||
pub fn format_bool(&self, input: bool) -> Result<String, FormatSpecError> {
|
||||
@@ -789,7 +801,13 @@ impl FormatSpec {
|
||||
}
|
||||
};
|
||||
let magnitude_str = self.add_magnitude_separators(raw_magnitude_str?, sign_str);
|
||||
self.format_sign_and_align(&AsciiStr::new(&magnitude_str), sign_str, FormatAlign::Right)
|
||||
Ok(
|
||||
self.format_sign_and_align(
|
||||
&AsciiStr::new(&magnitude_str),
|
||||
sign_str,
|
||||
FormatAlign::Right,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -863,11 +881,11 @@ impl FormatSpec {
|
||||
};
|
||||
let sign_prefix = format!("{sign_str}{prefix}");
|
||||
let magnitude_str = self.add_magnitude_separators(raw_magnitude_str, &sign_prefix);
|
||||
self.format_sign_and_align(
|
||||
Ok(self.format_sign_and_align(
|
||||
&AsciiStr::new(&magnitude_str),
|
||||
&sign_prefix,
|
||||
FormatAlign::Right,
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn format_string<T>(&self, s: &T) -> Result<String, FormatSpecError>
|
||||
@@ -883,7 +901,7 @@ impl FormatSpec {
|
||||
Some(p) => s.deref().chars().take(p).collect(),
|
||||
None => s.deref().to_owned(),
|
||||
};
|
||||
self.format_sign_and_align(&truncated, "", FormatAlign::Left)
|
||||
Ok(self.format_sign_and_align(&truncated, "", FormatAlign::Left))
|
||||
}
|
||||
_ => {
|
||||
let ch = char::from(self.format_type.as_ref().unwrap());
|
||||
@@ -905,7 +923,11 @@ impl FormatSpec {
|
||||
}
|
||||
match &self.fill.unwrap_or_else(|| ' '.into()).to_char() {
|
||||
Some('0') => Err(FormatSpecError::ZeroPadding),
|
||||
_ => self.format_sign_and_align(&AsciiStr::new(&magnitude_str), "", FormatAlign::Right),
|
||||
_ => Ok(self.format_sign_and_align(
|
||||
&AsciiStr::new(&magnitude_str),
|
||||
"",
|
||||
FormatAlign::Right,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1039,7 @@ impl FormatSpec {
|
||||
magnitude_str: &T,
|
||||
sign_str: &str,
|
||||
default_align: FormatAlign,
|
||||
) -> Result<String, FormatSpecError>
|
||||
) -> String
|
||||
where
|
||||
T: CharLen + Deref<Target = str>,
|
||||
{
|
||||
@@ -1030,7 +1052,7 @@ impl FormatSpec {
|
||||
});
|
||||
|
||||
let magnitude_str = magnitude_str.deref();
|
||||
Ok(match align {
|
||||
match align {
|
||||
FormatAlign::Left => format!(
|
||||
"{}{}{}",
|
||||
sign_str,
|
||||
@@ -1057,7 +1079,7 @@ impl FormatSpec {
|
||||
Self::compute_fill_string(fill_char, right_fill_chars_needed);
|
||||
format!("{left_fill_string}{sign_str}{magnitude_str}{right_fill_string}")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ pub fn pyclass(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
#[must_use]
|
||||
pub fn pyexception(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
if matches!(item, syn::Item::Impl(_)) {
|
||||
result_to_tokens(pyclass::impl_pyexception_impl(attr, item))
|
||||
pyclass::impl_pyexception_impl(attr, item)
|
||||
} else {
|
||||
result_to_tokens(pyclass::impl_pyexception(attr, item))
|
||||
}
|
||||
@@ -84,7 +84,7 @@ pub fn py_freeze(input: TokenStream, compiler: &dyn Compiler) -> TokenStream {
|
||||
|
||||
#[must_use]
|
||||
pub fn pypayload(input: DeriveInput) -> TokenStream {
|
||||
result_to_tokens(pypayload::impl_pypayload(input))
|
||||
pypayload::impl_pypayload(input)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
||||
@@ -644,8 +644,8 @@ pub(crate) fn impl_pyclass(attr: PunctuatedNestedMeta, item: Item) -> Result<Tok
|
||||
// 1. no `clear`: HAS_CLEAR = HAS_TRAVERSE (default: same as traverse)
|
||||
// 2. `clear` or `clear = true`: HAS_CLEAR = true, try_clear calls Traverse::clear
|
||||
// 3. `clear = false`: HAS_CLEAR = false (rare: traverse without clear)
|
||||
let has_traverse = class_meta.inner()._has_key("traverse")?;
|
||||
let has_clear = if class_meta.inner()._has_key("clear")? {
|
||||
let has_traverse = class_meta.inner()._has_key("traverse");
|
||||
let has_clear = if class_meta.inner()._has_key("clear") {
|
||||
// If clear attribute is present, use its value
|
||||
class_meta.inner()._bool("clear")?
|
||||
} else {
|
||||
@@ -804,9 +804,9 @@ pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: Item) -> Result
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> Result<TokenStream> {
|
||||
pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> TokenStream {
|
||||
let Item::Impl(imp) = item else {
|
||||
return Ok(item.into_token_stream());
|
||||
return item.into_token_stream();
|
||||
};
|
||||
|
||||
// Check if with(Constructor) is specified. If Constructor trait is used, don't generate slot_new
|
||||
@@ -878,7 +878,7 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
|
||||
quote!(, #(#extra_attrs),*)
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
quote! {
|
||||
#[pyclass(flags(BASETYPE, HAS_DICT), with(#(#with_items),*) #extra_attrs_tokens)]
|
||||
impl #generics #self_ty {
|
||||
#(#items)*
|
||||
@@ -886,7 +886,7 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
|
||||
|
||||
#slot_new
|
||||
#slot_init
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_content_item {
|
||||
@@ -1189,7 +1189,7 @@ where
|
||||
args.cfgs.to_vec(),
|
||||
tokens,
|
||||
2,
|
||||
)?;
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1235,7 +1235,7 @@ where
|
||||
|
||||
args.context
|
||||
.attribute_items
|
||||
.add_item(ident.clone(), vec![py_name], cfgs, tokens, 1)?;
|
||||
.add_item(ident.clone(), vec![py_name], cfgs, tokens, 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1944,12 +1944,12 @@ fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result<Extrac
|
||||
fn impl_item_new<Item>(
|
||||
index: usize,
|
||||
attr_name: AttrName,
|
||||
) -> Result<Box<dyn ImplItem<Item, AttrName = AttrName>>>
|
||||
) -> Box<dyn ImplItem<Item, AttrName = AttrName>>
|
||||
where
|
||||
Item: ItemLike + ToTokens + GetIdent,
|
||||
{
|
||||
use AttrName::*;
|
||||
Ok(match attr_name {
|
||||
match attr_name {
|
||||
attr_name @ (Method | ClassMethod | StaticMethod) => Box::new(MethodItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
@@ -1968,7 +1968,7 @@ where
|
||||
Member => Box::new(MemberItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn attrs_to_content_items<F, R>(
|
||||
@@ -1976,7 +1976,7 @@ fn attrs_to_content_items<F, R>(
|
||||
item_new: F,
|
||||
) -> Result<(Vec<R>, Vec<Attribute>)>
|
||||
where
|
||||
F: Fn(usize, AttrName) -> Result<R>,
|
||||
F: Fn(usize, AttrName) -> R,
|
||||
{
|
||||
let mut cfgs: Vec<Attribute> = Vec::new();
|
||||
let mut result = Vec::new();
|
||||
@@ -2018,7 +2018,7 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
result.push(item_new(i, attr_name)?);
|
||||
result.push(item_new(i, attr_name));
|
||||
}
|
||||
Ok((result, cfgs))
|
||||
}
|
||||
|
||||
@@ -816,7 +816,7 @@ impl ModuleItem for ClassItem {
|
||||
#set_attr
|
||||
},
|
||||
0,
|
||||
)?;
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -910,7 +910,7 @@ impl ModuleItem for StructSequenceItem {
|
||||
#set_attr
|
||||
},
|
||||
0,
|
||||
)?;
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -995,9 +995,9 @@ impl ModuleItem for AttributeItem {
|
||||
cfgs.clone(),
|
||||
tokens,
|
||||
1,
|
||||
)?;
|
||||
);
|
||||
Ok(())
|
||||
})?;
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
other => {
|
||||
@@ -1053,7 +1053,7 @@ impl ModuleItem for AttributeItem {
|
||||
|
||||
args.context
|
||||
.attribute_items
|
||||
.add_item(ident, py_names, cfgs, tokens, 1)?;
|
||||
.add_item(ident, py_names, cfgs, tokens, 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{DeriveInput, Result};
|
||||
use syn::DeriveInput;
|
||||
|
||||
pub(crate) fn impl_pypayload(input: DeriveInput) -> Result<TokenStream> {
|
||||
pub(crate) fn impl_pypayload(input: DeriveInput) -> TokenStream {
|
||||
let ty = &input.ident;
|
||||
|
||||
let ret = quote! {
|
||||
quote! {
|
||||
impl ::rustpython_vm::PyPayload for #ty {
|
||||
#[inline]
|
||||
fn class(_ctx: &::rustpython_vm::vm::Context) -> &'static rustpython_vm::Py<::rustpython_vm::builtins::PyType> {
|
||||
<Self as ::rustpython_vm::class::StaticType>::static_type()
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ impl ItemNursery {
|
||||
cfgs: Vec<Attribute>,
|
||||
tokens: TokenStream,
|
||||
sort_order: usize,
|
||||
) -> Result<()> {
|
||||
) {
|
||||
self.0.push(NurseryItem {
|
||||
attr_name,
|
||||
py_names,
|
||||
@@ -53,7 +53,6 @@ impl ItemNursery {
|
||||
tokens,
|
||||
sort_order,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn validate(self) -> Result<ValidatedItemNursery> {
|
||||
@@ -216,8 +215,8 @@ impl ItemMetaInner {
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub(crate) fn _has_key(&self, key: &str) -> Result<bool> {
|
||||
Ok(matches!(self.meta_map.get(key), Some((_, _))))
|
||||
pub(crate) fn _has_key(&self, key: &str) -> bool {
|
||||
matches!(self.meta_map.get(key), Some((_, _)))
|
||||
}
|
||||
|
||||
pub(crate) fn _bool(&self, key: &str) -> Result<bool> {
|
||||
|
||||
@@ -609,7 +609,7 @@ pub(crate) mod _asyncio {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn _callbacks(&self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
fn _callbacks(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let mut result = Vec::new();
|
||||
|
||||
if let Some(cb0) = self.fut_callback0.read().clone() {
|
||||
@@ -630,9 +630,9 @@ pub(crate) mod _asyncio {
|
||||
|
||||
// Return None if no callbacks
|
||||
if result.is_empty() {
|
||||
Ok(vm.ctx.none())
|
||||
vm.ctx.none()
|
||||
} else {
|
||||
Ok(vm.ctx.new_list(result).into())
|
||||
vm.ctx.new_list(result).into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,10 +764,10 @@ pub(crate) mod _asyncio {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __await__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyFutureIter> {
|
||||
Ok(PyFutureIter {
|
||||
fn __await__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyFutureIter {
|
||||
PyFutureIter {
|
||||
future: PyRwLock::new(Some(zelf.into())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclassmethod]
|
||||
@@ -861,23 +861,23 @@ pub(crate) mod _asyncio {
|
||||
.and_then(|asyncio| asyncio.get_attr(vm.ctx.intern_str("base_futures"), vm))
|
||||
{
|
||||
Ok(m) => m,
|
||||
Err(_) => return get_future_repr_info_fallback(future, vm),
|
||||
Err(_) => return Ok(get_future_repr_info_fallback(future, vm)),
|
||||
}
|
||||
};
|
||||
|
||||
let func = match vm.get_attribute_opt(module, vm.ctx.intern_str("_future_repr_info")) {
|
||||
Ok(Some(f)) => f,
|
||||
_ => return get_future_repr_info_fallback(future, vm),
|
||||
_ => return Ok(get_future_repr_info_fallback(future, vm)),
|
||||
};
|
||||
|
||||
let info = match func.call((future.to_owned(),), vm) {
|
||||
Ok(i) => i,
|
||||
Err(_) => return get_future_repr_info_fallback(future, vm),
|
||||
Err(_) => return Ok(get_future_repr_info_fallback(future, vm)),
|
||||
};
|
||||
|
||||
let list: PyListRef = match info.downcast() {
|
||||
Ok(l) => l,
|
||||
Err(_) => return get_future_repr_info_fallback(future, vm),
|
||||
Err(_) => return Ok(get_future_repr_info_fallback(future, vm)),
|
||||
};
|
||||
|
||||
let mut result = Wtf8Buf::new();
|
||||
@@ -893,17 +893,17 @@ pub(crate) mod _asyncio {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn get_future_repr_info_fallback(future: &PyObject, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
|
||||
fn get_future_repr_info_fallback(future: &PyObject, vm: &VirtualMachine) -> Wtf8Buf {
|
||||
// Fallback: build repr from properties directly
|
||||
if let Ok(Some(state)) =
|
||||
vm.get_attribute_opt(future.to_owned(), vm.ctx.intern_str("_state"))
|
||||
{
|
||||
let s = state
|
||||
state
|
||||
.str(vm)
|
||||
.map_or_else(|_| Wtf8Buf::from("unknown"), |s| s.as_wtf8().to_lowercase());
|
||||
return Ok(s);
|
||||
.map_or_else(|_| Wtf8Buf::from("unknown"), |s| s.as_wtf8().to_lowercase())
|
||||
} else {
|
||||
Wtf8Buf::from("state=unknown")
|
||||
}
|
||||
Ok(Wtf8Buf::from("state=unknown"))
|
||||
}
|
||||
|
||||
fn get_task_repr_info(task: &PyObject, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
|
||||
@@ -1820,10 +1820,10 @@ pub(crate) mod _asyncio {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __await__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyFutureIter> {
|
||||
Ok(PyFutureIter {
|
||||
fn __await__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyFutureIter {
|
||||
PyFutureIter {
|
||||
future: PyRwLock::new(Some(zelf.into())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclassmethod]
|
||||
@@ -1960,7 +1960,7 @@ pub(crate) mod _asyncio {
|
||||
_register_eager_task(task_obj.clone(), vm)?;
|
||||
|
||||
// Swap current task - save previous task
|
||||
let prev_task = _swap_current_task(loop_obj.clone(), task_obj.clone(), vm)?;
|
||||
let prev_task = _swap_current_task(loop_obj.clone(), task_obj.clone(), vm);
|
||||
|
||||
// Get coro and context
|
||||
let coro = zelf.task_coro.read().clone();
|
||||
@@ -2525,7 +2525,11 @@ pub(crate) mod _asyncio {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn _swap_current_task(loop_: PyObjectRef, task: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn _swap_current_task(
|
||||
loop_: PyObjectRef,
|
||||
task: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyObjectRef {
|
||||
// Per-thread swap, matching CPython's swap_current_task
|
||||
let prev = vm
|
||||
.asyncio_running_task
|
||||
@@ -2550,7 +2554,7 @@ pub(crate) mod _asyncio {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(prev)
|
||||
prev
|
||||
}
|
||||
|
||||
/// Reset task state after fork in child process.
|
||||
|
||||
@@ -165,12 +165,9 @@ mod _opcode {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_executor(
|
||||
_code: PyObjectRef,
|
||||
_offset: i32,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyObjectRef> {
|
||||
Ok(vm.ctx.none())
|
||||
fn get_executor(_code: PyObjectRef, _offset: i32, vm: &VirtualMachine) -> PyObjectRef {
|
||||
// TODO
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -2211,12 +2211,11 @@ mod _sqlite3 {
|
||||
)]
|
||||
impl Row {
|
||||
#[pymethod]
|
||||
fn keys(&self, _vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
Ok(self
|
||||
.description
|
||||
fn keys(&self, _vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
self.description
|
||||
.iter()
|
||||
.map(|x| x.downcast_ref::<PyTuple>().unwrap().as_slice()[0].clone())
|
||||
.collect())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn subscript(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
|
||||
|
||||
@@ -140,9 +140,9 @@ mod _contextvars {
|
||||
})
|
||||
}
|
||||
|
||||
fn contains(&self, needle: &Py<ContextVar>) -> PyResult<bool> {
|
||||
fn contains(&self, needle: &Py<ContextVar>) -> bool {
|
||||
let vars = self.borrow_vars();
|
||||
Ok(vars.get(needle).is_some())
|
||||
vars.get(needle).is_some()
|
||||
}
|
||||
|
||||
fn get_inner(&self, needle: &Py<ContextVar>) -> Option<PyObjectRef> {
|
||||
@@ -202,13 +202,13 @@ mod _contextvars {
|
||||
&self,
|
||||
key: PyRef<ContextVar>,
|
||||
default: OptionalArg<PyObjectRef>,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
) -> Option<PyObjectRef> {
|
||||
let found = self.get_inner(&key);
|
||||
Ok(if found.is_some() {
|
||||
if found.is_some() {
|
||||
found
|
||||
} else {
|
||||
default.into_option()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: wrong return type
|
||||
@@ -265,7 +265,7 @@ mod _contextvars {
|
||||
static AS_SEQUENCE: LazyLock<PySequenceMethods> = LazyLock::new(|| PySequenceMethods {
|
||||
contains: atomic_func!(|seq, target, vm| {
|
||||
let target = target.try_to_value(vm)?;
|
||||
PyContext::sequence_downcast(seq).contains(target)
|
||||
Ok(PyContext::sequence_downcast(seq).contains(target))
|
||||
}),
|
||||
..PySequenceMethods::NOT_IMPLEMENTED
|
||||
});
|
||||
@@ -335,7 +335,7 @@ mod _contextvars {
|
||||
}
|
||||
|
||||
// contextvar_set in CPython
|
||||
fn set_inner(zelf: &Py<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn set_inner(zelf: &Py<Self>, value: PyObjectRef, vm: &VirtualMachine) {
|
||||
let ctx = PyContext::current(vm);
|
||||
|
||||
let mut vars = ctx.borrow_vars_mut();
|
||||
@@ -348,8 +348,6 @@ mod _contextvars {
|
||||
idx: ctx.inner.idx.get(),
|
||||
};
|
||||
zelf.cached.store(Some(cache));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyHash {
|
||||
@@ -408,11 +406,7 @@ mod _contextvars {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn set(
|
||||
zelf: &Py<Self>,
|
||||
value: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyRef<ContextToken>> {
|
||||
fn set(zelf: &Py<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyRef<ContextToken> {
|
||||
let ctx = PyContext::current(vm);
|
||||
|
||||
let old_value = ctx.borrow_vars().get(zelf).map(|v| v.to_owned());
|
||||
@@ -424,9 +418,9 @@ mod _contextvars {
|
||||
};
|
||||
|
||||
// ctx.vars borrow must be released
|
||||
Self::set_inner(zelf, value, vm)?;
|
||||
Self::set_inner(zelf, value, vm);
|
||||
|
||||
Ok(token.into_ref(&vm.ctx))
|
||||
token.into_ref(&vm.ctx)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -456,7 +450,7 @@ mod _contextvars {
|
||||
token.used.set(true);
|
||||
|
||||
if let Some(old_value) = &token.old_value {
|
||||
Self::set_inner(zelf, old_value.clone(), vm)?;
|
||||
Self::set_inner(zelf, old_value.clone(), vm);
|
||||
} else {
|
||||
Self::delete(zelf, vm)?;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ mod grp {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn getgrall(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
fn getgrall(vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
// setgrent, getgrent, etc are not thread safe. Could use fgetgrent_r, but this is easier
|
||||
static GETGRALL: parking_lot::Mutex<()> = parking_lot::Mutex::new(());
|
||||
let _guard = GETGRALL.lock();
|
||||
@@ -98,6 +98,6 @@ mod grp {
|
||||
}
|
||||
unsafe { libc::endgrent() };
|
||||
|
||||
Ok(list)
|
||||
list
|
||||
}
|
||||
}
|
||||
@@ -99,12 +99,15 @@ mod _locale {
|
||||
vm.ctx.new_list(group_vec)
|
||||
}
|
||||
|
||||
unsafe fn pystr_from_raw_cstr(vm: &VirtualMachine, raw_ptr: *const libc::c_char) -> PyResult {
|
||||
unsafe fn pystr_from_raw_cstr(
|
||||
vm: &VirtualMachine,
|
||||
raw_ptr: *const libc::c_char,
|
||||
) -> PyObjectRef {
|
||||
let slice = unsafe { CStr::from_ptr(raw_ptr) };
|
||||
|
||||
// Fast path: ASCII/UTF-8
|
||||
if let Ok(s) = slice.to_str() {
|
||||
return Ok(vm.new_pyobj(s));
|
||||
return vm.new_pyobj(s);
|
||||
}
|
||||
|
||||
// On Windows, locale strings use the ANSI code page encoding
|
||||
@@ -131,12 +134,12 @@ mod _locale {
|
||||
wide.as_mut_ptr(),
|
||||
len,
|
||||
);
|
||||
return Ok(vm.new_pyobj(String::from_utf16_lossy(&wide)));
|
||||
return vm.new_pyobj(String::from_utf16_lossy(&wide));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(vm.new_pyobj(String::from_utf8_lossy(slice.to_bytes()).into_owned()))
|
||||
vm.new_pyobj(String::from_utf8_lossy(slice.to_bytes()).into_owned())
|
||||
}
|
||||
|
||||
#[pyattr(name = "Error", once)]
|
||||
@@ -179,7 +182,7 @@ mod _locale {
|
||||
($lc:expr, $field:ident) => {{
|
||||
result.set_item(
|
||||
stringify!($field),
|
||||
pystr_from_raw_cstr(vm, (*$lc).$field)?,
|
||||
pystr_from_raw_cstr(vm, (*$lc).$field),
|
||||
vm,
|
||||
)?
|
||||
}};
|
||||
@@ -264,6 +267,7 @@ mod _locale {
|
||||
if cfg!(windows) && (args.category < LC_ALL || args.category > LC_TIME) {
|
||||
return Err(vm.new_exception_msg(error, "unsupported locale setting".into()));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let result = match args.locale.flatten() {
|
||||
None => libc::setlocale(args.category, ptr::null()),
|
||||
@@ -288,10 +292,12 @@ mod _locale {
|
||||
libc::setlocale(args.category, c_locale.as_ptr())
|
||||
}
|
||||
};
|
||||
|
||||
if result.is_null() {
|
||||
return Err(vm.new_exception_msg(error, "unsupported locale setting".into()));
|
||||
}
|
||||
pystr_from_raw_cstr(vm, result)
|
||||
|
||||
Ok(pystr_from_raw_cstr(vm, result))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1345,8 +1345,8 @@ mod mmap {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn tell(&self) -> PyResult<usize> {
|
||||
Ok(self.pos())
|
||||
fn tell(&self) -> usize {
|
||||
self.pos()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -1867,7 +1867,7 @@ mod _overlapped {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn FormatMessage(error_code: u32, _vm: &VirtualMachine) -> PyResult<String> {
|
||||
fn FormatMessage(error_code: u32, _vm: &VirtualMachine) -> String {
|
||||
use windows_sys::Win32::Foundation::LocalFree;
|
||||
use windows_sys::Win32::System::Diagnostics::Debug::{
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
@@ -1898,7 +1898,7 @@ mod _overlapped {
|
||||
if !buffer.is_null() {
|
||||
unsafe { LocalFree(buffer as *mut _) };
|
||||
}
|
||||
return Ok(format!("unknown error code {}", error_code));
|
||||
return format!("unknown error code {error_code}");
|
||||
}
|
||||
|
||||
// Convert to Rust string, trimming trailing whitespace
|
||||
@@ -1907,7 +1907,7 @@ mod _overlapped {
|
||||
|
||||
unsafe { LocalFree(buffer as *mut _) };
|
||||
|
||||
Ok(msg)
|
||||
msg
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -124,9 +124,9 @@ mod _pyexpat {
|
||||
namespace_separator: Option<String>,
|
||||
intern: Option<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyExpatLikeXmlParserRef> {
|
||||
) -> PyExpatLikeXmlParserRef {
|
||||
let intern_dict = intern.unwrap_or_else(|| vm.ctx.new_dict().into());
|
||||
Ok(Self {
|
||||
Self {
|
||||
namespace_separator,
|
||||
start_element: MutableObject::new(vm.ctx.none()),
|
||||
end_element: MutableObject::new(vm.ctx.none()),
|
||||
@@ -157,7 +157,7 @@ mod _pyexpat {
|
||||
attlist_decl: MutableObject::new(vm.ctx.none()),
|
||||
skipped_entity: MutableObject::new(vm.ctx.none()),
|
||||
}
|
||||
.into_ref(&vm.ctx))
|
||||
.into_ref(&vm.ctx)
|
||||
}
|
||||
|
||||
#[extend_class]
|
||||
@@ -353,21 +353,21 @@ mod _pyexpat {
|
||||
data: Either<PyStrRef, PyBytesRef>,
|
||||
_isfinal: OptionalArg<bool>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<i32> {
|
||||
) -> i32 {
|
||||
let bytes = match data {
|
||||
Either::A(s) => s.as_bytes().to_vec(),
|
||||
Either::B(b) => b.as_bytes().to_vec(),
|
||||
};
|
||||
// Empty data is valid - used to finalize parsing
|
||||
if bytes.is_empty() {
|
||||
return Ok(1);
|
||||
return 1;
|
||||
}
|
||||
let reader = Cursor::<Vec<u8>>::new(bytes);
|
||||
let parser = self.create_config().create_reader(reader);
|
||||
// Note: xml-rs is stricter than libexpat; some errors are silently ignored
|
||||
// to maintain compatibility with existing Python code
|
||||
let _ = self.do_parse(vm, parser);
|
||||
Ok(1)
|
||||
1
|
||||
}
|
||||
|
||||
#[pymethod(name = "ParseFile")]
|
||||
@@ -417,7 +417,7 @@ mod _pyexpat {
|
||||
// encoding parameter is currently not used (xml-rs handles encoding from XML declaration)
|
||||
let _ = args.encoding;
|
||||
|
||||
PyExpatLikeXmlParser::new(ns_sep, args.intern, vm)
|
||||
Ok(PyExpatLikeXmlParser::new(ns_sep, args.intern, vm))
|
||||
}
|
||||
|
||||
// TODO: Tie this exception to the module's state.
|
||||
|
||||
@@ -40,6 +40,7 @@ mod decl {
|
||||
stdlib::time,
|
||||
};
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
#[cfg(windows)]
|
||||
crate::vm::windows::init_winsock();
|
||||
@@ -275,17 +276,12 @@ mod decl {
|
||||
#[pyclass]
|
||||
impl PyPoll {
|
||||
#[pymethod]
|
||||
fn register(
|
||||
&self,
|
||||
Fildes(fd): Fildes,
|
||||
eventmask: OptionalArg<EventMask>,
|
||||
) -> PyResult<()> {
|
||||
fn register(&self, Fildes(fd): Fildes, eventmask: OptionalArg<EventMask>) {
|
||||
let mask = match eventmask {
|
||||
OptionalArg::Present(event_mask) => event_mask.0,
|
||||
OptionalArg::Missing => DEFAULT_EVENTS,
|
||||
};
|
||||
insert_fd(&mut self.fds.lock(), fd, mask);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -13,6 +13,7 @@ mod _sha256 {
|
||||
Ok(local_sha256(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
let _ = vm.import("_hashlib", 0);
|
||||
__module_exec(vm, module);
|
||||
|
||||
@@ -13,6 +13,7 @@ mod _sha512 {
|
||||
Ok(local_sha512(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
let _ = vm.import("_hashlib", 0);
|
||||
__module_exec(vm, module);
|
||||
|
||||
@@ -24,6 +24,7 @@ mod _socket {
|
||||
};
|
||||
use rustpython_host_env::os::ErrorExt;
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
#[cfg(windows)]
|
||||
crate::vm::windows::init_winsock();
|
||||
@@ -31,6 +32,7 @@ mod _socket {
|
||||
__module_exec(vm, module);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use core::{
|
||||
mem::MaybeUninit,
|
||||
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
@@ -2067,7 +2069,7 @@ mod _socket {
|
||||
};
|
||||
|
||||
// Build ancdata list
|
||||
let ancdata = Self::parse_ancillary_data(&msg, vm)?;
|
||||
let ancdata = Self::parse_ancillary_data(&msg, vm);
|
||||
|
||||
// Build address tuple
|
||||
let address = if msg.msg_namelen > 0 {
|
||||
@@ -2089,7 +2091,7 @@ mod _socket {
|
||||
|
||||
/// Parse ancillary data from a received message header
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
fn parse_ancillary_data(msg: &libc::msghdr, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
fn parse_ancillary_data(msg: &libc::msghdr, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let mut result = Vec::new();
|
||||
|
||||
// Calculate buffer end for truncation handling
|
||||
@@ -2120,7 +2122,7 @@ mod _socket {
|
||||
cmsg = unsafe { libc::CMSG_NXTHDR(msg, cmsg) };
|
||||
}
|
||||
|
||||
Ok(vm.ctx.new_list(result).into())
|
||||
vm.ctx.new_list(result).into()
|
||||
}
|
||||
|
||||
// based on nix's implementation
|
||||
|
||||
+25
-41
@@ -1517,7 +1517,7 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn get_ciphers(&self, vm: &VirtualMachine) -> PyResult<PyListRef> {
|
||||
fn get_ciphers(&self, vm: &VirtualMachine) -> PyListRef {
|
||||
// Dynamically generate cipher list from rustls ALL_CIPHER_SUITES
|
||||
// This automatically includes all cipher suites supported by the current rustls version
|
||||
|
||||
@@ -1575,7 +1575,7 @@ mod _ssl {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(PyListRef::from(vm.ctx.new_list(cipher_list)))
|
||||
PyListRef::from(vm.ctx.new_list(cipher_list))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -2427,10 +2427,10 @@ mod _ssl {
|
||||
}
|
||||
|
||||
// Create and store a session object after successful handshake
|
||||
fn create_session_after_handshake(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn create_session_after_handshake(&self, vm: &VirtualMachine) {
|
||||
// Only create session for client-side connections
|
||||
if self.server_side {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if session already exists
|
||||
@@ -2438,7 +2438,7 @@ mod _ssl {
|
||||
if let Some(ref s) = session_opt {
|
||||
if vm.is_none(s) {
|
||||
} else {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2489,8 +2489,6 @@ mod _ssl {
|
||||
let py_session = session.into_pyobject(vm);
|
||||
|
||||
*self.session.write() = Some(py_session);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Complete handshake and create session
|
||||
@@ -2550,7 +2548,7 @@ mod _ssl {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn complete_handshake(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn complete_handshake(&self, vm: &VirtualMachine) {
|
||||
*self.handshake_done.lock() = true;
|
||||
|
||||
// Check if session was resumed - get value and release lock immediately
|
||||
@@ -2580,8 +2578,7 @@ mod _ssl {
|
||||
let _ = self.track_used_ca_from_capath();
|
||||
}
|
||||
|
||||
self.create_session_after_handshake(vm)?;
|
||||
Ok(())
|
||||
self.create_session_after_handshake(vm);
|
||||
}
|
||||
|
||||
// Internal implementation with timeout control
|
||||
@@ -3435,7 +3432,7 @@ mod _ssl {
|
||||
if is_client {
|
||||
// CLIENT is simple - no SNI callback handling needed
|
||||
handshake_result.map_err(|e| e.into_py_err(vm))?;
|
||||
self.complete_handshake(vm)?;
|
||||
self.complete_handshake(vm);
|
||||
Ok(())
|
||||
} else {
|
||||
// Use OpenSSL-compatible handshake for server
|
||||
@@ -3443,7 +3440,7 @@ mod _ssl {
|
||||
match handshake_result {
|
||||
Ok(()) => {
|
||||
// Handshake completed successfully
|
||||
self.complete_handshake(vm)?;
|
||||
self.complete_handshake(vm);
|
||||
Ok(())
|
||||
}
|
||||
Err(SslError::SniCallbackRestart) => {
|
||||
@@ -3662,13 +3659,13 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn pending(&self) -> PyResult<usize> {
|
||||
fn pending(&self) -> usize {
|
||||
// Returns the number of already decrypted bytes available for read
|
||||
// This is critical for asyncore's readable() method which checks socket.pending() > 0
|
||||
let mut conn_guard = self.connection.lock();
|
||||
let conn = match conn_guard.as_mut() {
|
||||
Some(c) => c,
|
||||
None => return Ok(0), // No connection established yet
|
||||
None => return 0, // No connection established yet
|
||||
};
|
||||
|
||||
// Use rustls Reader's fill_buf() to check buffered plaintext
|
||||
@@ -3676,11 +3673,11 @@ mod _ssl {
|
||||
// This matches OpenSSL's SSL_pending() behavior
|
||||
let mut reader = conn.reader();
|
||||
match reader.fill_buf() {
|
||||
Ok(buf) => Ok(buf.len()),
|
||||
Ok(buf) => buf.len(),
|
||||
Err(_) => {
|
||||
// WouldBlock or other errors mean no data available
|
||||
// Return 0 like OpenSSL does when buffer is empty
|
||||
Ok(0)
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3857,9 +3854,8 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pygetset(setter)]
|
||||
fn set_owner(&self, owner: PyObjectRef, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn set_owner(&self, owner: PyObjectRef, _vm: &VirtualMachine) {
|
||||
*self.owner.write() = Some(owner);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
@@ -3873,7 +3869,7 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pygetset(setter)]
|
||||
fn set_context(&self, value: PyRef<PySSLContext>, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn set_context(&self, value: PyRef<PySSLContext>, _vm: &VirtualMachine) {
|
||||
// Update context reference immediately
|
||||
// SSL_set_SSL_CTX allows context changes at any time,
|
||||
// even after handshake completion
|
||||
@@ -3881,8 +3877,6 @@ mod _ssl {
|
||||
|
||||
// Clear pending context as we've applied the change
|
||||
*self.pending_context.write() = None;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
@@ -3916,14 +3910,10 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn session(&self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
fn session(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
// Return the stored session object if any
|
||||
let sess = self.session.read().clone();
|
||||
if let Some(s) = sess {
|
||||
Ok(s)
|
||||
} else {
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
sess.unwrap_or_else(|| vm.ctx.none())
|
||||
}
|
||||
|
||||
#[pygetset(setter)]
|
||||
@@ -3999,18 +3989,12 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn get_verified_chain(&self, vm: &VirtualMachine) -> PyResult<Option<PyListRef>> {
|
||||
fn get_verified_chain(&self, vm: &VirtualMachine) -> Option<PyListRef> {
|
||||
// Get peer certificates (what peer sent during handshake)
|
||||
let conn_guard = self.connection.lock();
|
||||
let Some(ref conn) = *conn_guard else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let conn = (*conn_guard).as_ref()?;
|
||||
let peer_certs = conn.peer_certificates();
|
||||
|
||||
let Some(peer_certs_slice) = peer_certs else {
|
||||
return Ok(None);
|
||||
};
|
||||
let peer_certs_slice = peer_certs?;
|
||||
|
||||
// Build the verified chain using cert module
|
||||
let ctx_guard = self.context.read();
|
||||
@@ -4024,7 +4008,7 @@ mod _ssl {
|
||||
.map(|der_bytes| PySSLCertificate { der_bytes }.into_ref(&vm.ctx).into())
|
||||
.collect();
|
||||
|
||||
Ok(Some(vm.ctx.new_list(cert_list)))
|
||||
Some(vm.ctx.new_list(cert_list))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -4655,9 +4639,8 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn write_eof(&self, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn write_eof(&self, _vm: &VirtualMachine) {
|
||||
*self.eof.write() = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
@@ -4816,7 +4799,7 @@ mod _ssl {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_default_verify_paths(vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
fn get_default_verify_paths(vm: &VirtualMachine) -> PyObjectRef {
|
||||
// Return default certificate paths as a tuple
|
||||
// Lib/ssl.py expects: (openssl_cafile_env, openssl_cafile, openssl_capath_env, openssl_capath)
|
||||
// parts[0] = environment variable name for cafile
|
||||
@@ -4846,7 +4829,8 @@ mod _ssl {
|
||||
vm.ctx.new_str("SSL_CERT_DIR").into(), // openssl_capath_env
|
||||
default_capath.map_or_else(|| vm.ctx.none(), |s| vm.ctx.new_str(s).into()), // openssl_capath
|
||||
]);
|
||||
Ok(tuple.into())
|
||||
|
||||
tuple.into()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -292,8 +292,8 @@ pub(super) fn is_ca_certificate(cert_der: &[u8]) -> bool {
|
||||
/// Convert an X509Name to Python nested tuple format for SSL certificate dicts
|
||||
///
|
||||
/// Format: ((('CN', 'example.com'),), (('O', 'Example Org'),), ...)
|
||||
fn name_to_py(vm: &VirtualMachine, name: &x509_parser::x509::X509Name<'_>) -> PyResult {
|
||||
let list: Vec<PyObjectRef> = name
|
||||
fn name_to_py(vm: &VirtualMachine, name: &x509_parser::x509::X509Name<'_>) -> PyObjectRef {
|
||||
let list = name
|
||||
.iter()
|
||||
.flat_map(|rdn| {
|
||||
// Each RDN can have multiple attributes
|
||||
@@ -308,9 +308,9 @@ fn name_to_py(vm: &VirtualMachine, name: &x509_parser::x509::X509Name<'_>) -> Py
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect();
|
||||
.collect::<Vec<PyObjectRef>>();
|
||||
|
||||
Ok(vm.ctx.new_tuple(list).into())
|
||||
vm.ctx.new_tuple(list).into()
|
||||
}
|
||||
|
||||
/// Convert DER-encoded certificate to Python dict (for getpeercert with binary_form=False)
|
||||
@@ -324,8 +324,8 @@ pub(super) fn cert_to_dict(
|
||||
let dict = vm.ctx.new_dict();
|
||||
|
||||
// Subject and Issuer
|
||||
dict.set_item("subject", name_to_py(vm, cert.subject())?, vm)?;
|
||||
dict.set_item("issuer", name_to_py(vm, cert.issuer())?, vm)?;
|
||||
dict.set_item("subject", name_to_py(vm, cert.subject()), vm)?;
|
||||
dict.set_item("issuer", name_to_py(vm, cert.issuer()), vm)?;
|
||||
|
||||
// Version (X.509 v3 = version 2 in the cert, but Python uses 3)
|
||||
dict.set_item(
|
||||
|
||||
@@ -191,9 +191,9 @@ mod unicodedata {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn normalize(&self, form: super::NormalizeForm, unistr: PyStrRef) -> PyResult<Wtf8Buf> {
|
||||
fn normalize(&self, form: super::NormalizeForm, unistr: PyStrRef) -> Wtf8Buf {
|
||||
let text = unistr.as_wtf8();
|
||||
let normalized_text = match form {
|
||||
match form {
|
||||
Nfc => {
|
||||
let normalizer = ComposingNormalizerBorrowed::new_nfc();
|
||||
text.map_utf8(|s| normalizer.normalize_iter(s.chars()))
|
||||
@@ -214,12 +214,11 @@ mod unicodedata {
|
||||
text.map_utf8(|s| normalizer.normalize_iter(s.chars()))
|
||||
.collect()
|
||||
}
|
||||
};
|
||||
Ok(normalized_text)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn is_normalized(&self, form: super::NormalizeForm, unistr: PyStrRef) -> PyResult<bool> {
|
||||
fn is_normalized(&self, form: super::NormalizeForm, unistr: PyStrRef) -> bool {
|
||||
let text = unistr.as_wtf8();
|
||||
let normalized: Wtf8Buf = match form {
|
||||
Nfc => {
|
||||
@@ -243,7 +242,7 @@ mod unicodedata {
|
||||
.collect()
|
||||
}
|
||||
};
|
||||
Ok(text == &*normalized)
|
||||
text == &*normalized
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -766,12 +766,11 @@ impl PyAnextAwaitable {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn close(&self, vm: &VirtualMachine) {
|
||||
self.state.store(AwaitableState::Closed);
|
||||
if let Ok(awaitable) = self.get_awaitable_iter(vm) {
|
||||
let _ = vm.call_method(&awaitable, "close", ());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Convert StopAsyncIteration to StopIteration(default_value)
|
||||
|
||||
@@ -595,6 +595,7 @@ impl Frame {
|
||||
*storage = value.unwrap_or_none(vm);
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
#[pymember(type = "bool")]
|
||||
fn f_trace_lines(vm: &VirtualMachine, zelf: PyObjectRef) -> PyResult {
|
||||
let zelf: FrameRef = zelf.downcast().unwrap_or_else(|_| unreachable!());
|
||||
@@ -626,6 +627,7 @@ impl Frame {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
#[pymember(type = "bool")]
|
||||
fn f_trace_opcodes(vm: &VirtualMachine, zelf: PyObjectRef) -> PyResult {
|
||||
let zelf: FrameRef = zelf.downcast().unwrap_or_else(|_| unreachable!());
|
||||
|
||||
@@ -867,6 +867,7 @@ impl PyFunction {
|
||||
*self.name.lock() = name;
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
#[pymember]
|
||||
fn __doc__(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult {
|
||||
// When accessed from instance, obj is the PyFunction instance
|
||||
@@ -879,6 +880,7 @@ impl PyFunction {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
#[pymember(setter)]
|
||||
fn set___doc__(vm: &VirtualMachine, zelf: PyObjectRef, value: PySetterValue) -> PyResult<()> {
|
||||
let zelf: PyRef<Self> = zelf.downcast().unwrap_or_else(|_| unreachable!());
|
||||
|
||||
@@ -402,7 +402,7 @@ fn subs_tvars(
|
||||
}
|
||||
|
||||
// CPython's _unpack_args equivalent
|
||||
fn unpack_args(item: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn unpack_args(item: PyObjectRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let mut new_args = Vec::new();
|
||||
|
||||
let arg_items = if let Ok(tuple) = item.try_to_ref::<PyTuple>(vm) {
|
||||
@@ -442,7 +442,7 @@ fn unpack_args(item: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
new_args.push(item);
|
||||
}
|
||||
|
||||
Ok(PyTuple::new_ref(new_args, &vm.ctx))
|
||||
PyTuple::new_ref(new_args, &vm.ctx)
|
||||
}
|
||||
|
||||
// _Py_subs_parameters
|
||||
@@ -459,7 +459,7 @@ pub(crate) fn subs_parameters(
|
||||
}
|
||||
|
||||
// Step 1: Unpack args
|
||||
let mut item: PyObjectRef = unpack_args(item, vm)?.into();
|
||||
let mut item: PyObjectRef = unpack_args(item, vm).into();
|
||||
|
||||
// Step 2: Call __typing_prepare_subst__ on each parameter
|
||||
for param in parameters.iter() {
|
||||
|
||||
@@ -446,7 +446,7 @@ impl PyInt {
|
||||
zelf: PyRef<Self>,
|
||||
ndigits: OptionalOption<PyIntRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyRef<Self>> {
|
||||
) -> PyRef<Self> {
|
||||
if let Some(ndigits) = ndigits.flatten() {
|
||||
let ndigits = ndigits.as_bigint();
|
||||
// round(12345, -2) == 12300
|
||||
@@ -477,10 +477,10 @@ impl PyInt {
|
||||
BigInt::from(0)
|
||||
};
|
||||
let rounded = (rounded + correction) * sign;
|
||||
return Ok(vm.ctx.new_int(rounded));
|
||||
return vm.ctx.new_int(rounded);
|
||||
}
|
||||
}
|
||||
Ok(zelf)
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -61,24 +61,23 @@ impl PyMap {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn __reduce__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let cls = zelf.class().to_owned();
|
||||
let mut vec = vec![zelf.mapper.clone()];
|
||||
vec.extend(zelf.iterators.iter().map(|o| o.clone().into()));
|
||||
let tuple_args = vm.ctx.new_tuple(vec);
|
||||
Ok(if zelf.strict.load(atomic::Ordering::Acquire) {
|
||||
if zelf.strict.load(atomic::Ordering::Acquire) {
|
||||
vm.new_tuple((cls, tuple_args, true))
|
||||
} else {
|
||||
vm.new_tuple((cls, tuple_args))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __setstate__(zelf: PyRef<Self>, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn __setstate__(zelf: PyRef<Self>, state: PyObjectRef, vm: &VirtualMachine) {
|
||||
if let Ok(obj) = ArgIntoBool::try_from_object(vm, state) {
|
||||
zelf.strict.store(obj.into(), atomic::Ordering::Release);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ impl Constructor for PyBaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn generic_alloc(cls: PyTypeRef, _nitems: usize, vm: &VirtualMachine) -> PyResult {
|
||||
// Only create dict if the class has HAS_DICT flag (i.e., __slots__ was not defined
|
||||
// or __dict__ is in __slots__)
|
||||
@@ -542,6 +543,7 @@ impl PyBaseObject {
|
||||
common_reduce(obj, proto, vm)
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
#[pyslot]
|
||||
fn slot_hash(zelf: &PyObject, _vm: &VirtualMachine) -> PyResult<PyHash> {
|
||||
Ok(zelf.get_id() as _)
|
||||
|
||||
@@ -275,7 +275,7 @@ impl PyRange {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reversed__(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn __reversed__(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let start = self.start.as_bigint();
|
||||
let step = self.step.as_bigint();
|
||||
|
||||
@@ -285,29 +285,27 @@ impl PyRange {
|
||||
let start = &new_stop + length.clone() * step;
|
||||
let step = -step;
|
||||
|
||||
Ok(
|
||||
if let (Some(start), Some(step), Some(_)) =
|
||||
(start.to_isize(), step.to_isize(), new_stop.to_isize())
|
||||
{
|
||||
PyRangeIterator {
|
||||
index: AtomicCell::new(0),
|
||||
start,
|
||||
step,
|
||||
// Cannot fail. If start, stop and step all successfully convert to isize, then result of zelf.len will
|
||||
// always fit in a usize.
|
||||
length: length.to_usize().unwrap_or(0),
|
||||
}
|
||||
.into_pyobject(vm)
|
||||
} else {
|
||||
PyLongRangeIterator {
|
||||
index: AtomicCell::new(0),
|
||||
start,
|
||||
step,
|
||||
length,
|
||||
}
|
||||
.into_pyobject(vm)
|
||||
},
|
||||
)
|
||||
if let (Some(start), Some(step), Some(_)) =
|
||||
(start.to_isize(), step.to_isize(), new_stop.to_isize())
|
||||
{
|
||||
PyRangeIterator {
|
||||
index: AtomicCell::new(0),
|
||||
start,
|
||||
step,
|
||||
// Cannot fail. If start, stop and step all successfully convert to isize, then result of zelf.len will
|
||||
// always fit in a usize.
|
||||
length: length.to_usize().unwrap_or(0),
|
||||
}
|
||||
.into_pyobject(vm)
|
||||
} else {
|
||||
PyLongRangeIterator {
|
||||
index: AtomicCell::new(0),
|
||||
start,
|
||||
step,
|
||||
length,
|
||||
}
|
||||
.into_pyobject(vm)
|
||||
}
|
||||
}
|
||||
|
||||
fn __len__(&self) -> BigInt {
|
||||
@@ -618,7 +616,7 @@ impl PyLongRangeIterator {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn __reduce__(&self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
range_iter_reduce(
|
||||
self.start.clone(),
|
||||
self.length.clone(),
|
||||
@@ -680,7 +678,7 @@ impl PyRangeIterator {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn __reduce__(&self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
range_iter_reduce(
|
||||
BigInt::from(self.start),
|
||||
BigInt::from(self.length),
|
||||
@@ -721,7 +719,7 @@ fn range_iter_reduce(
|
||||
step: BigInt,
|
||||
index: usize,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyTupleRef> {
|
||||
) -> PyTupleRef {
|
||||
let iter = builtins_iter(vm);
|
||||
let stop = start.clone() + length * step.clone();
|
||||
let range = PyRange {
|
||||
@@ -729,7 +727,7 @@ fn range_iter_reduce(
|
||||
stop: PyInt::from(stop).into_ref(&vm.ctx),
|
||||
step: PyInt::from(step).into_ref(&vm.ctx),
|
||||
};
|
||||
Ok(vm.new_tuple((iter, (range,), index)))
|
||||
vm.new_tuple((iter, (range,), index))
|
||||
}
|
||||
|
||||
// Silently clips state (i.e index) in range [0, usize::MAX].
|
||||
|
||||
@@ -509,18 +509,15 @@ fn extract_set(obj: &PyObject) -> Option<&PySetInner> {
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_set(
|
||||
zelf: &PyObject,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<(PyTypeRef, PyTupleRef, Option<PyDictRef>)> {
|
||||
Ok((
|
||||
fn reduce_set(zelf: &PyObject, vm: &VirtualMachine) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
|
||||
(
|
||||
zelf.class().to_owned(),
|
||||
#[expect(clippy::or_fun_call, reason = "changing this won't compile")]
|
||||
vm.new_tuple((extract_set(zelf)
|
||||
.unwrap_or(&PySetInner::default())
|
||||
.elements(),)),
|
||||
zelf.dict(),
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
@@ -766,7 +763,7 @@ impl PySet {
|
||||
fn __reduce__(
|
||||
zelf: PyRef<Self>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<(PyTypeRef, PyTupleRef, Option<PyDictRef>)> {
|
||||
) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
|
||||
reduce_set(zelf.as_ref(), vm)
|
||||
}
|
||||
|
||||
@@ -1140,7 +1137,7 @@ impl PyFrozenSet {
|
||||
fn __reduce__(
|
||||
zelf: PyRef<Self>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<(PyTypeRef, PyTupleRef, Option<PyDictRef>)> {
|
||||
) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
|
||||
reduce_set(zelf.as_ref(), vm)
|
||||
}
|
||||
|
||||
@@ -1362,12 +1359,9 @@ impl PySetIterator {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(
|
||||
zelf: PyRef<Self>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<(PyObjectRef, (PyObjectRef,))> {
|
||||
fn __reduce__(zelf: PyRef<Self>, vm: &VirtualMachine) -> (PyObjectRef, (PyObjectRef,)) {
|
||||
let internal = zelf.internal.lock();
|
||||
Ok((
|
||||
(
|
||||
builtins_iter(vm),
|
||||
(vm.ctx
|
||||
.new_list(match &internal.status {
|
||||
@@ -1377,7 +1371,7 @@ impl PySetIterator {
|
||||
}
|
||||
})
|
||||
.into(),),
|
||||
))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -248,14 +248,14 @@ impl PySlice {
|
||||
#[pymethod]
|
||||
fn __reduce__(
|
||||
zelf: PyRef<Self>,
|
||||
) -> PyResult<(
|
||||
) -> (
|
||||
PyTypeRef,
|
||||
(Option<PyObjectRef>, PyObjectRef, Option<PyObjectRef>),
|
||||
)> {
|
||||
Ok((
|
||||
) {
|
||||
(
|
||||
zelf.class().to_owned(),
|
||||
(zelf.start.clone(), zelf.stop.clone(), zelf.step.clone()),
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Uncomment when Python adds __class_getitem__ to slice
|
||||
|
||||
@@ -1559,13 +1559,13 @@ impl PyStr {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __str__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
fn __str__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyStrRef {
|
||||
if zelf.class().is(vm.ctx.types.str_type) {
|
||||
// Already exact str, just return a reference
|
||||
Ok(zelf.to_owned())
|
||||
zelf.to_owned()
|
||||
} else {
|
||||
// Subclass, create a new exact str
|
||||
Ok(PyStr::from(zelf.data.clone()).into_ref(&vm.ctx))
|
||||
PyStr::from(zelf.data.clone()).into_ref(&vm.ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2667,10 +2667,10 @@ fn subtype_set_dict(obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine)
|
||||
}
|
||||
|
||||
// subtype_get_weakref
|
||||
fn subtype_get_weakref(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn subtype_get_weakref(obj: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
// Return the first weakref in the weakref list, or None
|
||||
let weakref = obj.get_weakrefs();
|
||||
Ok(weakref.unwrap_or_else(|| vm.ctx.none()))
|
||||
weakref.unwrap_or_else(|| vm.ctx.none())
|
||||
}
|
||||
|
||||
// subtype_set_weakref: __weakref__ is read-only
|
||||
|
||||
@@ -47,7 +47,7 @@ impl Constructor for PyZip {
|
||||
#[pyclass(with(IterNext, Iterable, Constructor), flags(BASETYPE))]
|
||||
impl PyZip {
|
||||
#[pymethod]
|
||||
fn __reduce__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn __reduce__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let cls = zelf.class().to_owned();
|
||||
let iterators = zelf
|
||||
.iterators
|
||||
@@ -55,23 +55,23 @@ impl PyZip {
|
||||
.map(|obj| obj.clone().into())
|
||||
.collect::<Vec<_>>();
|
||||
let tuple_iter = vm.ctx.new_tuple(iterators);
|
||||
Ok(if zelf.strict.load(atomic::Ordering::Acquire) {
|
||||
if zelf.strict.load(atomic::Ordering::Acquire) {
|
||||
vm.new_tuple((cls, tuple_iter, true))
|
||||
} else {
|
||||
vm.new_tuple((cls, tuple_iter))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __setstate__(zelf: PyRef<Self>, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn __setstate__(zelf: PyRef<Self>, state: PyObjectRef, vm: &VirtualMachine) {
|
||||
if let Ok(obj) = ArgIntoBool::try_from_object(vm, state) {
|
||||
zelf.strict.store(obj.into(), atomic::Ordering::Release);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SelfIter for PyZip {}
|
||||
|
||||
impl IterNext for PyZip {
|
||||
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
if zelf.iterators.is_empty() {
|
||||
|
||||
@@ -214,31 +214,30 @@ impl CodecsRegistry {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unregister(&self, search_function: PyObjectRef) -> PyResult<()> {
|
||||
pub fn unregister(&self, search_function: PyObjectRef) {
|
||||
let mut inner = self.inner.write();
|
||||
// Do nothing if search_path is not created yet or was cleared.
|
||||
if inner.search_path.is_empty() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
for (i, item) in inner.search_path.iter().enumerate() {
|
||||
if item.get_id() == search_function.get_id() {
|
||||
if !inner.search_cache.is_empty() {
|
||||
inner.search_cache.clear();
|
||||
}
|
||||
inner.search_path.remove(i);
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn register_manual(&self, name: &str, codec: PyCodec) -> PyResult<()> {
|
||||
pub(crate) fn register_manual(&self, name: &str, codec: PyCodec) {
|
||||
let name = normalize_encoding_name(name);
|
||||
self.inner
|
||||
.write()
|
||||
.search_cache
|
||||
.insert(name.into_owned(), codec);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lookup(&self, encoding: &str, vm: &VirtualMachine) -> PyResult<PyCodec> {
|
||||
|
||||
+20
-32
@@ -392,15 +392,6 @@ fn print_source_line<W: Write>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "host_env"))]
|
||||
fn print_source_line<W: Write>(
|
||||
_output: &mut W,
|
||||
_filename: &str,
|
||||
_lineno: usize,
|
||||
) -> Result<(), W::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Print exception occurrence location from traceback element
|
||||
fn write_traceback_entry<W: Write>(
|
||||
output: &mut W,
|
||||
@@ -414,6 +405,8 @@ fn write_traceback_entry<W: Write>(
|
||||
tb_entry.lineno,
|
||||
tb_entry.frame.code.obj_name
|
||||
)?;
|
||||
|
||||
#[cfg(feature = "host_env")]
|
||||
print_source_line(output, filename, tb_entry.lineno.get())?;
|
||||
|
||||
Ok(())
|
||||
@@ -674,22 +667,22 @@ impl PyBaseException {
|
||||
#[pyclass]
|
||||
impl Py<PyBaseException> {
|
||||
#[pymethod]
|
||||
pub(super) fn __str__(&self, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
pub(super) fn __str__(&self, vm: &VirtualMachine) -> PyStrRef {
|
||||
let str_args = vm.exception_args_as_string(self.args(), true);
|
||||
Ok(match str_args.into_iter().exactly_one() {
|
||||
match str_args.into_iter().exactly_one() {
|
||||
Err(i) if i.len() == 0 => vm.ctx.empty_str.to_owned(),
|
||||
Ok(s) => s,
|
||||
Err(i) => PyStr::from(format!("({})", i.format(", "))).into_ref(&vm.ctx),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
impl PyRef<PyBaseException> {
|
||||
#[pymethod]
|
||||
fn with_traceback(self, tb: Option<PyTracebackRef>) -> PyResult<Self> {
|
||||
fn with_traceback(self, tb: Option<PyTracebackRef>) -> Self {
|
||||
*self.traceback.write() = tb;
|
||||
Ok(self)
|
||||
self
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -1092,11 +1085,7 @@ fn make_arg_getter(idx: usize) -> impl Fn(PyBaseExceptionRef) -> Option<PyObject
|
||||
move |exc| exc.get_arg(idx)
|
||||
}
|
||||
|
||||
fn syntax_error_set_msg(
|
||||
exc: PyBaseExceptionRef,
|
||||
value: PySetterValue,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
fn syntax_error_set_msg(exc: PyBaseExceptionRef, value: PySetterValue, vm: &VirtualMachine) {
|
||||
let mut args = exc.args.write();
|
||||
let mut new_args = args.as_slice().to_vec();
|
||||
// Ensure the message slot at index 0 always exists for SyntaxError.args.
|
||||
@@ -1108,7 +1097,6 @@ fn syntax_error_set_msg(
|
||||
PySetterValue::Delete => new_args[0] = vm.ctx.none(),
|
||||
}
|
||||
*args = PyTuple::new_ref(new_args, &vm.ctx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn system_exit_code(exc: PyBaseExceptionRef) -> Option<PyObjectRef> {
|
||||
@@ -1117,11 +1105,11 @@ fn system_exit_code(exc: PyBaseExceptionRef) -> Option<PyObjectRef> {
|
||||
// - size == 1: code is args[0]
|
||||
// - size > 1: code is args (the whole tuple)
|
||||
let args = exc.args.read();
|
||||
match args.len() {
|
||||
0 => None,
|
||||
1 => Some(args.first().unwrap().clone()),
|
||||
_ => Some(args.as_object().to_owned()),
|
||||
}
|
||||
Some(match args.len() {
|
||||
0 => return None,
|
||||
1 => args.first().unwrap().clone(),
|
||||
_ => args.as_object().to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
@@ -1712,16 +1700,16 @@ pub(super) mod types {
|
||||
#[pyexception]
|
||||
impl PyKeyError {
|
||||
#[pymethod]
|
||||
fn __str__(zelf: &Py<PyBaseException>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
fn __str__(zelf: &Py<PyBaseException>, vm: &VirtualMachine) -> PyStrRef {
|
||||
let args = zelf.args();
|
||||
Ok(if args.len() == 1 {
|
||||
if args.len() == 1 {
|
||||
vm.exception_args_as_string(args, false)
|
||||
.into_iter()
|
||||
.exactly_one()
|
||||
.unwrap()
|
||||
} else {
|
||||
zelf.__str__(vm)?
|
||||
})
|
||||
zelf.__str__(vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2065,7 +2053,7 @@ pub(super) mod types {
|
||||
}
|
||||
|
||||
// fallback to BaseException.__str__
|
||||
zelf.__str__(vm)
|
||||
Ok(zelf.__str__(vm))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -2334,7 +2322,7 @@ pub(super) mod types {
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PySyntaxError {
|
||||
#[pymethod]
|
||||
fn __str__(zelf: &Py<PyBaseException>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
fn __str__(zelf: &Py<PyBaseException>, vm: &VirtualMachine) -> PyStrRef {
|
||||
fn basename(filename: &Wtf8) -> &Wtf8 {
|
||||
let bytes = filename.as_bytes();
|
||||
let pos = if cfg!(windows) {
|
||||
@@ -2387,7 +2375,7 @@ pub(super) mod types {
|
||||
(None, None) => msg.as_wtf8().to_owned(),
|
||||
};
|
||||
|
||||
Ok(vm.ctx.new_str(msg_with_location_info))
|
||||
vm.ctx.new_str(msg_with_location_info)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2194,7 +2194,7 @@ impl ExecutingFrame<'_> {
|
||||
self.push_value(set.into());
|
||||
Ok(None)
|
||||
}
|
||||
Instruction::BuildSlice { argc } => self.execute_build_slice(vm, argc.get(arg)),
|
||||
Instruction::BuildSlice { argc } => Ok(self.execute_build_slice(vm, argc.get(arg))),
|
||||
/*
|
||||
Instruction::ToBool => {
|
||||
dbg!("Shouldn't be called outside of match statements for now")
|
||||
@@ -6471,7 +6471,7 @@ impl ExecutingFrame<'_> {
|
||||
&mut self,
|
||||
vm: &VirtualMachine,
|
||||
argc: bytecode::BuildSliceArgCount,
|
||||
) -> FrameResult {
|
||||
) -> Option<ExecutionResult> {
|
||||
let step = match argc {
|
||||
bytecode::BuildSliceArgCount::Two => None,
|
||||
bytecode::BuildSliceArgCount::Three => Some(self.pop_value()),
|
||||
@@ -6486,7 +6486,7 @@ impl ExecutingFrame<'_> {
|
||||
}
|
||||
.into_ref(&vm.ctx);
|
||||
self.push_value(obj.into());
|
||||
Ok(None)
|
||||
None
|
||||
}
|
||||
|
||||
fn collect_positional_args(&mut self, nargs: u32) -> FuncArgs {
|
||||
|
||||
@@ -414,7 +414,7 @@ pub(crate) fn parse(
|
||||
};
|
||||
let obj = top.ast_to_object(vm, &source_file);
|
||||
if type_comments && obj.class().is(pyast::NodeModModule::static_type()) {
|
||||
let type_ignores = type_ignores_from_source(vm, source)?;
|
||||
let type_ignores = type_ignores_from_source(vm, source);
|
||||
let dict = obj.as_object().dict().unwrap();
|
||||
dict.set_item("type_ignores", vm.ctx.new_list(type_ignores).into(), vm)
|
||||
.unwrap();
|
||||
@@ -512,10 +512,7 @@ pub(crate) fn parse_func_type(
|
||||
Ok(func_type.ast_to_object(vm, &source_file))
|
||||
}
|
||||
|
||||
fn type_ignores_from_source(
|
||||
vm: &VirtualMachine,
|
||||
source: &str,
|
||||
) -> Result<Vec<PyObjectRef>, CompileError> {
|
||||
fn type_ignores_from_source(vm: &VirtualMachine, source: &str) -> Vec<PyObjectRef> {
|
||||
let mut ignores = Vec::new();
|
||||
for (idx, line) in source.lines().enumerate() {
|
||||
let Some(pos) = line.find("#") else {
|
||||
@@ -542,7 +539,7 @@ fn type_ignores_from_source(
|
||||
.unwrap();
|
||||
ignores.push(node.into());
|
||||
}
|
||||
Ok(ignores)
|
||||
ignores
|
||||
}
|
||||
|
||||
#[cfg(feature = "parser")]
|
||||
|
||||
@@ -23,8 +23,8 @@ mod _codecs {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn unregister(search_function: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
vm.state.codec_registry.unregister(search_function)
|
||||
fn unregister(search_function: PyObjectRef, vm: &VirtualMachine) {
|
||||
vm.state.codec_registry.unregister(search_function);
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -251,11 +251,11 @@ mod _collections {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reversed__(zelf: PyRef<Self>) -> PyResult<PyReverseDequeIterator> {
|
||||
Ok(PyReverseDequeIterator {
|
||||
fn __reversed__(zelf: PyRef<Self>) -> PyReverseDequeIterator {
|
||||
PyReverseDequeIterator {
|
||||
state: zelf.state.load(),
|
||||
internal: PyMutex::new(PositionIterInternal::new(zelf, 0)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -688,7 +688,7 @@ mod _collections {
|
||||
(DequeIterArgs { deque, index }, _kwargs): Self::Args,
|
||||
_vm: &VirtualMachine,
|
||||
) -> PyResult<Self> {
|
||||
let iter = PyDeque::__reversed__(deque)?;
|
||||
let iter = PyDeque::__reversed__(deque);
|
||||
if let OptionalArg::Present(index) = index {
|
||||
let index = max(index, 0) as usize;
|
||||
iter.internal.lock().position = index;
|
||||
@@ -708,20 +708,21 @@ mod _collections {
|
||||
fn __reduce__(
|
||||
zelf: PyRef<Self>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<(PyTypeRef, (PyDequeRef, PyObjectRef))> {
|
||||
) -> (PyTypeRef, (PyDequeRef, PyObjectRef)) {
|
||||
let internal = zelf.internal.lock();
|
||||
let deque = match &internal.status {
|
||||
Active(obj) => obj.clone(),
|
||||
Exhausted => PyDeque::default().into_ref(&vm.ctx),
|
||||
};
|
||||
Ok((
|
||||
(
|
||||
zelf.class().to_owned(),
|
||||
(deque, vm.ctx.new_int(internal.position).into()),
|
||||
))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl SelfIter for PyReverseDequeIterator {}
|
||||
|
||||
impl IterNext for PyReverseDequeIterator {
|
||||
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
zelf.internal.lock().next(|deque, pos| {
|
||||
|
||||
@@ -547,13 +547,13 @@ pub(crate) mod _ctypes {
|
||||
name: String,
|
||||
_load_flags: OptionalArg<i32>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<usize> {
|
||||
) -> usize {
|
||||
// TODO: audit functions first
|
||||
// TODO: load_flags
|
||||
let cache = library::libcache();
|
||||
let mut cache_write = cache.write();
|
||||
let (id, _) = cache_write.get_or_insert_lib(&name, vm).unwrap();
|
||||
Ok(id)
|
||||
id
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@@ -585,13 +585,9 @@ pub(crate) mod _ctypes {
|
||||
if handle.is_null() {
|
||||
let err = unsafe { libc::dlerror() };
|
||||
let msg = if err.is_null() {
|
||||
"dlopen() error".to_string()
|
||||
"dlopen() error"
|
||||
} else {
|
||||
unsafe {
|
||||
core::ffi::CStr::from_ptr(err)
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
}
|
||||
unsafe { &core::ffi::CStr::from_ptr(err).to_string_lossy() }
|
||||
};
|
||||
return Err(vm.new_os_error(msg));
|
||||
}
|
||||
@@ -605,22 +601,20 @@ pub(crate) mod _ctypes {
|
||||
}
|
||||
|
||||
#[pyfunction(name = "FreeLibrary")]
|
||||
fn free_library(handle: usize) -> PyResult<()> {
|
||||
fn free_library(handle: usize) {
|
||||
let cache = library::libcache();
|
||||
let mut cache_write = cache.write();
|
||||
cache_write.drop_lib(handle);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[pyfunction]
|
||||
fn dlclose(handle: usize, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn dlclose(handle: usize, _vm: &VirtualMachine) {
|
||||
// Remove from cache, which triggers SharedLibrary drop.
|
||||
// libloading::Library calls dlclose automatically on Drop.
|
||||
let cache = library::libcache();
|
||||
let mut cache_write = cache.write();
|
||||
cache_write.drop_lib(handle);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@@ -747,13 +741,13 @@ pub(crate) mod _ctypes {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[pyfunction(name = "_check_HRESULT")]
|
||||
fn check_hresult(_self: PyObjectRef, hr: i32, _vm: &VirtualMachine) -> PyResult<i32> {
|
||||
fn check_hresult(_self: PyObjectRef, hr: i32, _vm: &VirtualMachine) -> i32 {
|
||||
// TODO: fixme
|
||||
if hr < 0 {
|
||||
// vm.ctx.new_windows_error(hr)
|
||||
todo!();
|
||||
} else {
|
||||
Ok(hr)
|
||||
hr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,8 +957,8 @@ pub(crate) mod _ctypes {
|
||||
|
||||
#[cfg(windows)]
|
||||
#[pyfunction]
|
||||
fn get_last_error() -> PyResult<u32> {
|
||||
Ok(super::function::get_last_error_value())
|
||||
fn get_last_error() -> u32 {
|
||||
super::function::get_last_error_value()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -1195,7 +1189,7 @@ pub(crate) mod _ctypes {
|
||||
|
||||
#[cfg(windows)]
|
||||
#[pyfunction(name = "FormatError")]
|
||||
fn format_error_func(code: OptionalArg<u32>, _vm: &VirtualMachine) -> PyResult<String> {
|
||||
fn format_error_func(code: OptionalArg<u32>, _vm: &VirtualMachine) -> String {
|
||||
use windows_sys::Win32::Foundation::{GetLastError, LocalFree};
|
||||
use windows_sys::Win32::System::Diagnostics::Debug::{
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
@@ -1220,22 +1214,20 @@ pub(crate) mod _ctypes {
|
||||
};
|
||||
|
||||
if len == 0 || buffer.is_null() {
|
||||
return Ok("<no description>".to_string());
|
||||
return "<no description>".to_string();
|
||||
}
|
||||
|
||||
let message = unsafe {
|
||||
unsafe {
|
||||
let slice = core::slice::from_raw_parts(buffer, len as usize);
|
||||
let msg = String::from_utf16_lossy(slice).trim_end().to_string();
|
||||
LocalFree(buffer as *mut _);
|
||||
msg
|
||||
};
|
||||
|
||||
Ok(message)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[pyfunction(name = "CopyComPointer")]
|
||||
fn copy_com_pointer(src: PyObjectRef, dst: PyObjectRef, vm: &VirtualMachine) -> PyResult<i32> {
|
||||
fn copy_com_pointer(src: PyObjectRef, dst: PyObjectRef, vm: &VirtualMachine) -> i32 {
|
||||
use windows_sys::Win32::Foundation::{E_POINTER, S_OK};
|
||||
|
||||
// 1. Extract pointer-to-pointer address from dst (byref() result)
|
||||
@@ -1244,15 +1236,15 @@ pub(crate) mod _ctypes {
|
||||
let base = if let Some(cdata) = carg.obj.downcast_ref::<PyCData>() {
|
||||
cdata.buffer.read().as_ptr() as usize
|
||||
} else {
|
||||
return Ok(E_POINTER);
|
||||
return E_POINTER;
|
||||
};
|
||||
(base as isize + carg.offset) as usize
|
||||
} else {
|
||||
return Ok(E_POINTER);
|
||||
return E_POINTER;
|
||||
};
|
||||
|
||||
if pdst == 0 {
|
||||
return Ok(E_POINTER);
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// 2. Extract COM pointer value from src
|
||||
@@ -1271,7 +1263,7 @@ pub(crate) mod _ctypes {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
return Ok(E_POINTER);
|
||||
return E_POINTER;
|
||||
};
|
||||
|
||||
// 3. Call IUnknown::AddRef if src is non-NULL
|
||||
@@ -1292,9 +1284,10 @@ pub(crate) mod _ctypes {
|
||||
*(pdst as *mut usize) = src_ptr;
|
||||
}
|
||||
|
||||
Ok(S_OK)
|
||||
S_OK
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(
|
||||
vm: &VirtualMachine,
|
||||
module: &Py<crate::builtins::PyModule>,
|
||||
|
||||
@@ -613,13 +613,13 @@ impl PyCArray {
|
||||
};
|
||||
|
||||
let buffer = buffer_lock.read();
|
||||
Self::read_element_from_buffer(
|
||||
Ok(Self::read_element_from_buffer(
|
||||
&buffer,
|
||||
final_offset,
|
||||
element_size,
|
||||
type_code.as_deref(),
|
||||
vm,
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
/// Helper to read an element value from a buffer at given offset
|
||||
@@ -629,14 +629,14 @@ impl PyCArray {
|
||||
element_size: usize,
|
||||
type_code: Option<&str>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
) -> PyObjectRef {
|
||||
match type_code {
|
||||
Some("c") => {
|
||||
// Return single byte as bytes
|
||||
if offset < buffer.len() {
|
||||
Ok(vm.ctx.new_bytes(vec![buffer[offset]]).into())
|
||||
vm.ctx.new_bytes(vec![buffer[offset]]).into()
|
||||
} else {
|
||||
Ok(vm.ctx.new_bytes(vec![0]).into())
|
||||
vm.ctx.new_bytes(vec![0]).into()
|
||||
}
|
||||
}
|
||||
Some("u") => {
|
||||
@@ -645,25 +645,28 @@ impl PyCArray {
|
||||
let s = char::from_u32(code)
|
||||
.map(|c| c.to_string())
|
||||
.unwrap_or_default();
|
||||
Ok(vm.ctx.new_str(s).into())
|
||||
vm.ctx.new_str(s).into()
|
||||
} else {
|
||||
Ok(vm.ctx.new_str("").into())
|
||||
vm.ctx.new_str("").into()
|
||||
}
|
||||
}
|
||||
Some("z") => {
|
||||
// c_char_p: pointer to bytes - dereference to get string
|
||||
if offset + element_size > buffer.len() {
|
||||
return Ok(vm.ctx.none());
|
||||
return vm.ctx.none();
|
||||
}
|
||||
|
||||
let ptr_bytes = &buffer[offset..offset + element_size];
|
||||
let ptr_val = usize::from_ne_bytes(
|
||||
ptr_bytes
|
||||
.try_into()
|
||||
.unwrap_or([0; core::mem::size_of::<usize>()]),
|
||||
);
|
||||
|
||||
if ptr_val == 0 {
|
||||
return Ok(vm.ctx.none());
|
||||
return vm.ctx.none();
|
||||
}
|
||||
|
||||
// Read null-terminated string from pointer address
|
||||
unsafe {
|
||||
let ptr = ptr_val as *const u8;
|
||||
@@ -672,23 +675,26 @@ impl PyCArray {
|
||||
len += 1;
|
||||
}
|
||||
let bytes = core::slice::from_raw_parts(ptr, len);
|
||||
Ok(vm.ctx.new_bytes(bytes.to_vec()).into())
|
||||
vm.ctx.new_bytes(bytes.to_vec()).into()
|
||||
}
|
||||
}
|
||||
Some("Z") => {
|
||||
// c_wchar_p: pointer to wchar_t - dereference to get string
|
||||
if offset + element_size > buffer.len() {
|
||||
return Ok(vm.ctx.none());
|
||||
return vm.ctx.none();
|
||||
}
|
||||
|
||||
let ptr_bytes = &buffer[offset..offset + element_size];
|
||||
let ptr_val = usize::from_ne_bytes(
|
||||
ptr_bytes
|
||||
.try_into()
|
||||
.unwrap_or([0; core::mem::size_of::<usize>()]),
|
||||
);
|
||||
|
||||
if ptr_val == 0 {
|
||||
return Ok(vm.ctx.none());
|
||||
return vm.ctx.none();
|
||||
}
|
||||
|
||||
// Read null-terminated wide string using WCHAR_SIZE
|
||||
unsafe {
|
||||
let ptr = ptr_val as *const u8;
|
||||
@@ -710,8 +716,9 @@ impl PyCArray {
|
||||
}
|
||||
pos += WCHAR_SIZE;
|
||||
}
|
||||
|
||||
let s: String = chars.into_iter().collect();
|
||||
Ok(vm.ctx.new_str(s).into())
|
||||
vm.ctx.new_str(s).into()
|
||||
}
|
||||
}
|
||||
Some("f") => {
|
||||
@@ -720,7 +727,7 @@ impl PyCArray {
|
||||
.first_chunk::<4>()
|
||||
.copied()
|
||||
.map_or(0.0, f32::from_ne_bytes);
|
||||
Ok(vm.ctx.new_float(val as f64).into())
|
||||
vm.ctx.new_float(val as f64).into()
|
||||
}
|
||||
Some("d" | "g") => {
|
||||
// c_double / c_longdouble - read f64 from first 8 bytes
|
||||
@@ -728,13 +735,13 @@ impl PyCArray {
|
||||
.first_chunk::<8>()
|
||||
.copied()
|
||||
.map_or(0.0, f64::from_ne_bytes);
|
||||
Ok(vm.ctx.new_float(val).into())
|
||||
vm.ctx.new_float(val).into()
|
||||
}
|
||||
_ => {
|
||||
if let Some(bytes) = buffer[offset..].get(..element_size) {
|
||||
Ok(Self::bytes_to_int(bytes, element_size, type_code, vm))
|
||||
Self::bytes_to_int(bytes, element_size, type_code, vm)
|
||||
} else {
|
||||
Ok(vm.ctx.new_int(0).into())
|
||||
vm.ctx.new_int(0).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1169,11 +1176,11 @@ impl AsBuffer for PyCArray {
|
||||
// CharArray and WCharArray getsets - added dynamically via add_getset
|
||||
|
||||
// CharArray_get_value
|
||||
fn char_array_get_value(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn char_array_get_value(obj: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let zelf = obj.downcast_ref::<PyCArray>().unwrap();
|
||||
let buffer = zelf.0.buffer.read();
|
||||
let len = buffer.iter().position(|&b| b == 0).unwrap_or(buffer.len());
|
||||
Ok(vm.ctx.new_bytes(buffer[..len].to_vec()).into())
|
||||
vm.ctx.new_bytes(buffer[..len].to_vec()).into()
|
||||
}
|
||||
|
||||
// CharArray_set_value
|
||||
@@ -1197,10 +1204,10 @@ fn char_array_set_value(obj: PyObjectRef, value: PyObjectRef, vm: &VirtualMachin
|
||||
}
|
||||
|
||||
// CharArray_get_raw
|
||||
fn char_array_get_raw(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn char_array_get_raw(obj: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let zelf = obj.downcast_ref::<PyCArray>().unwrap();
|
||||
let buffer = zelf.0.buffer.read();
|
||||
Ok(vm.ctx.new_bytes(buffer.to_vec()).into())
|
||||
vm.ctx.new_bytes(buffer.to_vec()).into()
|
||||
}
|
||||
|
||||
// CharArray_set_raw
|
||||
@@ -1222,10 +1229,10 @@ fn char_array_set_raw(
|
||||
}
|
||||
|
||||
// WCharArray_get_value
|
||||
fn wchar_array_get_value(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn wchar_array_get_value(obj: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let zelf = obj.downcast_ref::<PyCArray>().unwrap();
|
||||
let buffer = zelf.0.buffer.read();
|
||||
Ok(vm.ctx.new_str(wstring_from_bytes(&buffer)).into())
|
||||
vm.ctx.new_str(wstring_from_bytes(&buffer)).into()
|
||||
}
|
||||
|
||||
// WCharArray_set_value
|
||||
|
||||
@@ -1072,7 +1072,7 @@ impl PyCData {
|
||||
let (mut bytes, converted_value) = if let Some(type_code) = &field_type_code {
|
||||
PyCField::value_to_bytes_for_type(type_code, &value, size, vm)?
|
||||
} else {
|
||||
(PyCField::value_to_bytes(&value, size, vm)?, None)
|
||||
(PyCField::value_to_bytes(&value, size, vm), None)
|
||||
};
|
||||
|
||||
// Swap bytes for opposite endianness
|
||||
@@ -1479,11 +1479,10 @@ impl Constructor for PyCField {
|
||||
.try_to_value(vm)?;
|
||||
|
||||
// Validate byte_size matches the type
|
||||
let type_size = super::base::get_field_size(field_type.as_object(), vm)? as isize;
|
||||
let type_size = super::base::get_field_size(field_type.as_object(), vm) as isize;
|
||||
if byte_size != type_size {
|
||||
return Err(vm.new_value_error(format!(
|
||||
"byte_size {} does not match type size {}",
|
||||
byte_size, type_size
|
||||
"byte_size {byte_size} does not match type size {type_size}"
|
||||
)));
|
||||
}
|
||||
|
||||
@@ -1588,14 +1587,14 @@ impl GetDescriptor for PyCField {
|
||||
|
||||
impl PyCField {
|
||||
/// Convert a Python value to bytes
|
||||
fn value_to_bytes(value: &PyObject, size: usize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
|
||||
fn value_to_bytes(value: &PyObject, size: usize, vm: &VirtualMachine) -> Vec<u8> {
|
||||
// 1. Handle bytes objects
|
||||
if let Some(bytes) = value.downcast_ref::<PyBytes>() {
|
||||
let src = bytes.as_bytes();
|
||||
let mut result = vec![0u8; size];
|
||||
let len = core::cmp::min(src.len(), size);
|
||||
result[..len].copy_from_slice(&src[..len]);
|
||||
Ok(result)
|
||||
result
|
||||
}
|
||||
// 2. Handle ctypes array instances (copy their buffer)
|
||||
else if let Some(cdata) = value.downcast_ref::<super::PyCData>() {
|
||||
@@ -1603,7 +1602,7 @@ impl PyCField {
|
||||
let mut result = vec![0u8; size];
|
||||
let len = core::cmp::min(buffer.len(), size);
|
||||
result[..len].copy_from_slice(&buffer[..len]);
|
||||
Ok(result)
|
||||
result
|
||||
}
|
||||
// 4. Handle float values (check before int, since float.try_int would truncate)
|
||||
else if let Some(float_val) = value.downcast_ref::<crate::builtins::PyFloat>() {
|
||||
@@ -1611,9 +1610,9 @@ impl PyCField {
|
||||
match size {
|
||||
4 => {
|
||||
let val = f as f32;
|
||||
Ok(val.to_ne_bytes().to_vec())
|
||||
val.to_ne_bytes().to_vec()
|
||||
}
|
||||
8 => Ok(f.to_ne_bytes().to_vec()),
|
||||
8 => f.to_ne_bytes().to_vec(),
|
||||
_ => unreachable!("wrong payload size"),
|
||||
}
|
||||
}
|
||||
@@ -1623,24 +1622,24 @@ impl PyCField {
|
||||
match size {
|
||||
1 => {
|
||||
let val = i.to_i8().unwrap_or(0);
|
||||
Ok(val.to_ne_bytes().to_vec())
|
||||
val.to_ne_bytes().to_vec()
|
||||
}
|
||||
2 => {
|
||||
let val = i.to_i16().unwrap_or(0);
|
||||
Ok(val.to_ne_bytes().to_vec())
|
||||
val.to_ne_bytes().to_vec()
|
||||
}
|
||||
4 => {
|
||||
let val = i.to_i32().unwrap_or(0);
|
||||
Ok(val.to_ne_bytes().to_vec())
|
||||
val.to_ne_bytes().to_vec()
|
||||
}
|
||||
8 => {
|
||||
let val = i.to_i64().unwrap_or(0);
|
||||
Ok(val.to_ne_bytes().to_vec())
|
||||
val.to_ne_bytes().to_vec()
|
||||
}
|
||||
_ => Ok(vec![0u8; size]),
|
||||
_ => vec![0u8; size],
|
||||
}
|
||||
} else {
|
||||
Ok(vec![0u8; size])
|
||||
vec![0u8; size]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1712,7 +1711,7 @@ impl PyCField {
|
||||
if vm.is_none(value) {
|
||||
return Ok((vec![0u8; size], None));
|
||||
}
|
||||
Ok((PyCField::value_to_bytes(value, size, vm)?, None))
|
||||
Ok((PyCField::value_to_bytes(value, size, vm), None))
|
||||
}
|
||||
"Z" => {
|
||||
// c_wchar_p: store pointer to null-terminated wchar_t buffer
|
||||
@@ -1737,7 +1736,7 @@ impl PyCField {
|
||||
if vm.is_none(value) {
|
||||
return Ok((vec![0u8; size], None));
|
||||
}
|
||||
Ok((PyCField::value_to_bytes(value, size, vm)?, None))
|
||||
Ok((PyCField::value_to_bytes(value, size, vm), None))
|
||||
}
|
||||
"P" => {
|
||||
// c_void_p: store integer as pointer
|
||||
@@ -1753,9 +1752,9 @@ impl PyCField {
|
||||
if vm.is_none(value) {
|
||||
return Ok((vec![0u8; size], None));
|
||||
}
|
||||
Ok((PyCField::value_to_bytes(value, size, vm)?, None))
|
||||
Ok((PyCField::value_to_bytes(value, size, vm), None))
|
||||
}
|
||||
_ => Ok((PyCField::value_to_bytes(value, size, vm)?, None)),
|
||||
_ => Ok((PyCField::value_to_bytes(value, size, vm), None)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1947,7 +1946,7 @@ pub(super) fn call_paramfunc(obj: &PyObject, vm: &VirtualMachine) -> PyResult<CA
|
||||
ParamFunc::Simple => simple_paramfunc(obj, vm),
|
||||
ParamFunc::Array => array_paramfunc(obj, vm),
|
||||
ParamFunc::Pointer => pointer_paramfunc(obj, vm),
|
||||
ParamFunc::Structure | ParamFunc::Union => struct_union_paramfunc(obj, &stg_info, vm),
|
||||
ParamFunc::Structure | ParamFunc::Union => Ok(struct_union_paramfunc(obj, &stg_info, vm)),
|
||||
ParamFunc::None => Err(vm.new_type_error("no paramfunc")),
|
||||
}
|
||||
}
|
||||
@@ -2022,36 +2021,32 @@ fn pointer_paramfunc(obj: &PyObject, vm: &VirtualMachine) -> PyResult<CArgObject
|
||||
}
|
||||
|
||||
/// StructUnionType_paramfunc (for both Structure and Union)
|
||||
fn struct_union_paramfunc(
|
||||
obj: &PyObject,
|
||||
stg_info: &StgInfo,
|
||||
_vm: &VirtualMachine,
|
||||
) -> PyResult<CArgObject> {
|
||||
fn struct_union_paramfunc(obj: &PyObject, stg_info: &StgInfo, _vm: &VirtualMachine) -> CArgObject {
|
||||
// Get buffer pointer
|
||||
// For large structs (> sizeof(void*)), we'd need to allocate and copy.
|
||||
// For now, just point to buffer directly and keep obj reference for memory safety.
|
||||
let buffer = if let Some(cdata) = obj.downcast_ref::<PyCData>() {
|
||||
cdata.buffer.read()
|
||||
} else {
|
||||
return Ok(CArgObject {
|
||||
return CArgObject {
|
||||
tag: b'V',
|
||||
value: FfiArgValue::Pointer(0),
|
||||
obj: obj.to_owned(),
|
||||
size: stg_info.size,
|
||||
offset: 0,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
let ptr_val = buffer.as_ptr() as usize;
|
||||
let size = buffer.len();
|
||||
|
||||
Ok(CArgObject {
|
||||
CArgObject {
|
||||
tag: b'V',
|
||||
value: FfiArgValue::Pointer(ptr_val),
|
||||
obj: obj.to_owned(),
|
||||
size,
|
||||
offset: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// FfiArgValue - Owned FFI argument value
|
||||
@@ -2467,11 +2462,11 @@ pub(super) fn check_other_endian_support(
|
||||
}
|
||||
|
||||
/// Get the size of a ctypes field type
|
||||
pub(super) fn get_field_size(field_type: &PyObject, vm: &VirtualMachine) -> PyResult<usize> {
|
||||
pub(super) fn get_field_size(field_type: &PyObject, vm: &VirtualMachine) -> usize {
|
||||
if let Some(type_obj) = field_type.downcast_ref::<PyType>()
|
||||
&& let Some(stg_info) = type_obj.stg_info_opt()
|
||||
{
|
||||
return Ok(stg_info.size);
|
||||
return stg_info.size;
|
||||
}
|
||||
|
||||
if let Some(size) = field_type
|
||||
@@ -2483,7 +2478,7 @@ pub(super) fn get_field_size(field_type: &PyObject, vm: &VirtualMachine) -> PyRe
|
||||
(s.len() == 1).then(|| super::get_size(&s))
|
||||
})
|
||||
{
|
||||
return Ok(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
if let Some(s) = field_type
|
||||
@@ -2493,10 +2488,10 @@ pub(super) fn get_field_size(field_type: &PyObject, vm: &VirtualMachine) -> PyRe
|
||||
.and_then(|size| size.try_int(vm).ok())
|
||||
.and_then(|n| n.as_bigint().to_usize())
|
||||
{
|
||||
return Ok(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
Ok(core::mem::size_of::<usize>())
|
||||
core::mem::size_of::<usize>()
|
||||
}
|
||||
|
||||
/// Get the alignment of a ctypes field type
|
||||
|
||||
@@ -1903,14 +1903,13 @@ impl PyCFuncPtr {
|
||||
}
|
||||
|
||||
#[pygetset(name = "argtypes", setter)]
|
||||
fn set_argtypes(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn set_argtypes(&self, value: PyObjectRef, vm: &VirtualMachine) {
|
||||
if vm.is_none(&value) {
|
||||
*self.argtypes.write() = None;
|
||||
} else {
|
||||
// Store the argtypes object directly as it is
|
||||
*self.argtypes.write() = Some(value);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// errcheck getter/setter
|
||||
|
||||
@@ -418,7 +418,12 @@ impl PyCPointer {
|
||||
&& let Ok(type_str) = type_attr.str(vm)
|
||||
{
|
||||
let type_code = type_str.to_string();
|
||||
return Self::read_value_at_address(addr, element_size, Some(&type_code), vm);
|
||||
return Ok(Self::read_value_at_address(
|
||||
addr,
|
||||
element_size,
|
||||
Some(&type_code),
|
||||
vm,
|
||||
));
|
||||
}
|
||||
|
||||
// Complex type: create instance that references the memory directly (not a copy)
|
||||
@@ -658,55 +663,55 @@ impl PyCPointer {
|
||||
size: usize,
|
||||
type_code: Option<&str>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
) -> PyObjectRef {
|
||||
unsafe {
|
||||
let ptr = addr as *const u8;
|
||||
match type_code {
|
||||
// Single-byte types don't need read_unaligned
|
||||
Some("c") => Ok(vm.ctx.new_bytes(vec![*ptr]).into()),
|
||||
Some("b") => Ok(vm.ctx.new_int(*ptr as i8 as i32).into()),
|
||||
Some("B") => Ok(vm.ctx.new_int(*ptr as i32).into()),
|
||||
Some("c") => vm.ctx.new_bytes(vec![*ptr]).into(),
|
||||
Some("b") => vm.ctx.new_int(*ptr as i8 as i32).into(),
|
||||
Some("B") => vm.ctx.new_int(*ptr as i32).into(),
|
||||
// Multi-byte types need read_unaligned for safety on strict-alignment architectures
|
||||
Some("h") => Ok(vm
|
||||
Some("h") => vm
|
||||
.ctx
|
||||
.new_int(core::ptr::read_unaligned(ptr as *const i16) as i32)
|
||||
.into()),
|
||||
Some("H") => Ok(vm
|
||||
.into(),
|
||||
Some("H") => vm
|
||||
.ctx
|
||||
.new_int(core::ptr::read_unaligned(ptr as *const u16) as i32)
|
||||
.into()),
|
||||
Some("i" | "l") => Ok(vm
|
||||
.into(),
|
||||
Some("i" | "l") => vm
|
||||
.ctx
|
||||
.new_int(core::ptr::read_unaligned(ptr as *const i32))
|
||||
.into()),
|
||||
Some("I" | "L") => Ok(vm
|
||||
.into(),
|
||||
Some("I" | "L") => vm
|
||||
.ctx
|
||||
.new_int(core::ptr::read_unaligned(ptr as *const u32))
|
||||
.into()),
|
||||
Some("q") => Ok(vm
|
||||
.into(),
|
||||
Some("q") => vm
|
||||
.ctx
|
||||
.new_int(core::ptr::read_unaligned(ptr as *const i64))
|
||||
.into()),
|
||||
Some("Q") => Ok(vm
|
||||
.into(),
|
||||
Some("Q") => vm
|
||||
.ctx
|
||||
.new_int(core::ptr::read_unaligned(ptr as *const u64))
|
||||
.into()),
|
||||
Some("f") => Ok(vm
|
||||
.into(),
|
||||
Some("f") => vm
|
||||
.ctx
|
||||
.new_float(core::ptr::read_unaligned(ptr as *const f32) as f64)
|
||||
.into()),
|
||||
Some("d" | "g") => Ok(vm
|
||||
.into(),
|
||||
Some("d" | "g") => vm
|
||||
.ctx
|
||||
.new_float(core::ptr::read_unaligned(ptr as *const f64))
|
||||
.into()),
|
||||
Some("P" | "z" | "Z") => Ok(vm
|
||||
.into(),
|
||||
Some("P" | "z" | "Z") => vm
|
||||
.ctx
|
||||
.new_int(core::ptr::read_unaligned(ptr as *const usize))
|
||||
.into()),
|
||||
.into(),
|
||||
_ => {
|
||||
// Default: read as bytes
|
||||
let bytes = core::slice::from_raw_parts(ptr, size).to_vec();
|
||||
Ok(vm.ctx.new_bytes(bytes).into())
|
||||
vm.ctx.new_bytes(bytes).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ impl PyCStructType {
|
||||
}
|
||||
|
||||
// Get size and alignment of the field type
|
||||
let size = super::base::get_field_size(&field_type, vm)?;
|
||||
let size = super::base::get_field_size(&field_type, vm);
|
||||
let field_align = super::base::get_field_align(&field_type, vm);
|
||||
|
||||
// Calculate effective alignment (PyCField_FromDesc)
|
||||
|
||||
@@ -229,7 +229,7 @@ impl PyCUnionType {
|
||||
super::base::check_other_endian_support(&field_type, vm)?;
|
||||
}
|
||||
|
||||
let size = super::base::get_field_size(&field_type, vm)?;
|
||||
let size = super::base::get_field_size(&field_type, vm);
|
||||
let field_align = super::base::get_field_align(&field_type, vm);
|
||||
|
||||
// Calculate effective alignment
|
||||
|
||||
@@ -177,7 +177,7 @@ mod _functools {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
fn __reduce__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let inner = zelf.inner.read();
|
||||
let partial_type = zelf.class();
|
||||
|
||||
@@ -193,14 +193,13 @@ mod _functools {
|
||||
inner.keywords.clone().into(),
|
||||
dict_obj,
|
||||
]);
|
||||
Ok(vm
|
||||
.ctx
|
||||
vm.ctx
|
||||
.new_tuple(vec![
|
||||
partial_type.to_owned().into(),
|
||||
vm.ctx.new_tuple(vec![inner.func.clone()]).into(),
|
||||
state.into(),
|
||||
])
|
||||
.into())
|
||||
.into()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -183,8 +183,8 @@ mod _imp {
|
||||
use version::PYC_MAGIC_NUMBER_TOKEN;
|
||||
|
||||
#[pyfunction]
|
||||
const fn extension_suffixes() -> PyResult<Vec<PyObjectRef>> {
|
||||
Ok(Vec::new())
|
||||
const fn extension_suffixes() -> Vec<PyObjectRef> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -297,14 +297,12 @@ mod _imp {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn _frozen_module_names(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
let names = vm
|
||||
.state
|
||||
fn _frozen_module_names(vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
vm.state
|
||||
.frozen
|
||||
.keys()
|
||||
.map(|&name| vm.ctx.new_utf8_str(name).into())
|
||||
.collect();
|
||||
Ok(names)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
|
||||
@@ -1591,14 +1591,7 @@ mod _io {
|
||||
let zelf: PyRef<Self> = zelf.try_into_value(vm)?;
|
||||
let (raw, BufferSize { buffer_size }): (PyObjectRef, _) =
|
||||
args.bind(vm).map_err(|e| {
|
||||
let str_repr = e
|
||||
.__str__(vm)
|
||||
.as_ref()
|
||||
.map_or_else(
|
||||
|_| "<error getting exception str>".as_ref(),
|
||||
|s| s.as_wtf8(),
|
||||
)
|
||||
.to_owned();
|
||||
let str_repr = e.__str__(vm).as_wtf8().to_owned();
|
||||
let msg = format!("{}() {}", Self::CLASS_NAME, str_repr);
|
||||
vm.new_exception_msg(e.class().to_owned(), msg.into())
|
||||
})?;
|
||||
@@ -5310,6 +5303,10 @@ mod _io {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(feature = "host_env"),
|
||||
expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")
|
||||
)]
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
// Call auto-generated initialization first
|
||||
__module_exec(vm, module);
|
||||
@@ -5953,13 +5950,8 @@ mod fileio {
|
||||
|
||||
/// fileio_dealloc_warn in Modules/_io/fileio.c
|
||||
#[pymethod(name = "_dealloc_warn")]
|
||||
fn _dealloc_warn_method(
|
||||
zelf: &Py<Self>,
|
||||
source: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
fn _dealloc_warn_method(zelf: &Py<Self>, source: PyObjectRef, vm: &VirtualMachine) {
|
||||
Self::dealloc_warn(zelf, source, vm);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,13 +54,13 @@ mod _operator {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn is_(a: PyObjectRef, b: PyObjectRef) -> PyResult<bool> {
|
||||
Ok(a.is(&b))
|
||||
fn is_(a: PyObjectRef, b: PyObjectRef) -> bool {
|
||||
a.is(&b)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn is_not(a: PyObjectRef, b: PyObjectRef) -> PyResult<bool> {
|
||||
Ok(!a.is(&b))
|
||||
fn is_not(a: PyObjectRef, b: PyObjectRef) -> bool {
|
||||
!a.is(&b)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -363,11 +363,11 @@ mod _operator {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<(PyTypeRef, PyTupleRef)> {
|
||||
fn __reduce__(zelf: PyRef<Self>, vm: &VirtualMachine) -> (PyTypeRef, PyTupleRef) {
|
||||
let attrs = vm
|
||||
.ctx
|
||||
.new_tuple(zelf.attrs.iter().map(|v| v.clone().into()).collect());
|
||||
Ok((zelf.class().to_owned(), attrs))
|
||||
(zelf.class().to_owned(), attrs)
|
||||
}
|
||||
|
||||
// Go through dotted parts of string and call getattr on whatever is returned.
|
||||
|
||||
@@ -703,6 +703,7 @@ pub(crate) mod _signal {
|
||||
WAKEUP.store(INVALID_WAKEUP, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(
|
||||
vm: &VirtualMachine,
|
||||
module: &Py<crate::builtins::PyModule>,
|
||||
|
||||
@@ -172,9 +172,8 @@ mod _symtable {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn children(&self, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
let children = self
|
||||
.symtable
|
||||
fn children(&self, vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
self.symtable
|
||||
.sub_tables
|
||||
.iter()
|
||||
.flat_map(|t| {
|
||||
@@ -186,8 +185,7 @@ mod _symtable {
|
||||
}
|
||||
})
|
||||
.map(|t| to_py_symbol_table(t.clone()).into_pyobject(vm))
|
||||
.collect();
|
||||
Ok(children)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
@@ -196,24 +194,22 @@ mod _symtable {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn identifiers(&self, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
let symbols = self
|
||||
.symtable
|
||||
fn identifiers(&self, vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
self.symtable
|
||||
.symbols
|
||||
.keys()
|
||||
.map(|s| vm.ctx.new_str(s.as_str()).into())
|
||||
.collect();
|
||||
Ok(symbols)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn symbols(&self, vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
fn symbols(&self, vm: &VirtualMachine) -> PyDictRef {
|
||||
let dict = vm.ctx.new_dict();
|
||||
for (name, symbol) in &self.symtable.symbols {
|
||||
dict.set_item(name, vm.new_pyobj(symbol.flags.bits()), vm)
|
||||
.unwrap();
|
||||
}
|
||||
Ok(dict)
|
||||
dict
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
@@ -319,13 +315,11 @@ mod _symtable {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn get_namespaces(&self, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
let namespaces = self
|
||||
.namespaces
|
||||
fn get_namespaces(&self, vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
self.namespaces
|
||||
.iter()
|
||||
.map(|table| to_py_symbol_table(table.clone()).into_pyobject(vm))
|
||||
.collect();
|
||||
Ok(namespaces)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -140,11 +140,10 @@ pub(crate) mod _thread {
|
||||
|
||||
#[cfg(unix)]
|
||||
#[pymethod]
|
||||
fn _at_fork_reinit(&self, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn _at_fork_reinit(&self, _vm: &VirtualMachine) {
|
||||
// Overwrite lock state to unlocked. Do NOT call unlock() here —
|
||||
// after fork(), unlock_slow() would try to unpark stale waiters.
|
||||
unsafe { rustpython_common::lock::zero_reinit_after_fork(&self.mu) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -235,12 +234,11 @@ pub(crate) mod _thread {
|
||||
|
||||
#[cfg(unix)]
|
||||
#[pymethod]
|
||||
fn _at_fork_reinit(&self, _vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn _at_fork_reinit(&self, _vm: &VirtualMachine) {
|
||||
// Overwrite lock state to unlocked. Do NOT call unlock() here —
|
||||
// after fork(), unlock_slow() would try to unpark stale waiters.
|
||||
self.count.store(0, core::sync::atomic::Ordering::Relaxed);
|
||||
unsafe { rustpython_common::lock::zero_reinit_after_fork(&self.mu) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -44,13 +44,13 @@ pub(crate) mod decl {
|
||||
}
|
||||
|
||||
#[pyfunction(name = "override")]
|
||||
pub(crate) fn r#override(func: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
pub(crate) fn r#override(func: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
|
||||
// Set __override__ attribute to True
|
||||
// Skip the attribute silently if it is not writable.
|
||||
// AttributeError happens if the object has __slots__ or a
|
||||
// read-only property, TypeError if it's a builtin class.
|
||||
let _ = func.set_attr("__override__", vm.ctx.true_value.clone(), vm);
|
||||
Ok(func)
|
||||
func
|
||||
}
|
||||
|
||||
#[pyclass(no_attr, name = "NoDefaultType", module = "typing")]
|
||||
@@ -302,11 +302,11 @@ pub(crate) mod decl {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn evaluate_value(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn evaluate_value(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
if self.is_lazy {
|
||||
return Ok(self.compute_value.clone());
|
||||
return self.compute_value.clone();
|
||||
}
|
||||
Ok(const_evaluator_alloc(self.compute_value.clone(), vm))
|
||||
const_evaluator_alloc(self.compute_value.clone(), vm)
|
||||
}
|
||||
|
||||
/// Check type_params ordering: non-default params must precede default params.
|
||||
@@ -492,6 +492,7 @@ pub(crate) mod decl {
|
||||
Ok(PyTuple::new_ref(new_params, &vm.ctx))
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(
|
||||
vm: &VirtualMachine,
|
||||
module: &Py<crate::builtins::PyModule>,
|
||||
|
||||
@@ -928,7 +928,7 @@ mod builtins {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn oct(number: ArgIndex, vm: &VirtualMachine) -> PyResult {
|
||||
fn oct(number: ArgIndex, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let number = number.into_int_ref();
|
||||
let n = number.as_bigint();
|
||||
let s = if n.is_negative() {
|
||||
@@ -937,7 +937,7 @@ mod builtins {
|
||||
format!("0o{n:o}")
|
||||
};
|
||||
|
||||
Ok(vm.ctx.new_str(s).into())
|
||||
vm.ctx.new_str(s).into()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -956,12 +956,12 @@ mod decl {
|
||||
}
|
||||
|
||||
impl PyItertoolsTeeData {
|
||||
fn new(iterable: PyIter, _vm: &VirtualMachine) -> PyResult<PyRc<Self>> {
|
||||
Ok(PyRc::new(Self {
|
||||
fn new(iterable: PyIter, _vm: &VirtualMachine) -> PyRc<Self> {
|
||||
PyRc::new(Self {
|
||||
iterable,
|
||||
values: PyMutex::new(vec![]),
|
||||
running: AtomicBool::new(false),
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn get_item(&self, vm: &VirtualMachine, index: usize) -> PyResult<PyIterReturn> {
|
||||
@@ -1043,7 +1043,7 @@ mod decl {
|
||||
return vm.call_special_method(&iterator, identifier!(vm, __copy__), ());
|
||||
}
|
||||
Ok(Self {
|
||||
tee_data: PyItertoolsTeeData::new(iterator, vm)?,
|
||||
tee_data: PyItertoolsTeeData::new(iterator, vm),
|
||||
index: AtomicCell::new(0),
|
||||
}
|
||||
.into_ref_with_type(vm, class.to_owned())?
|
||||
|
||||
@@ -127,13 +127,13 @@ pub(crate) mod module {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
pub(super) fn _supports_virtual_terminal() -> PyResult<bool> {
|
||||
pub(super) fn _supports_virtual_terminal() -> bool {
|
||||
let mut mode = 0;
|
||||
let handle = unsafe { Console::GetStdHandle(Console::STD_ERROR_HANDLE) };
|
||||
if unsafe { Console::GetConsoleMode(handle, &mut mode) } == 0 {
|
||||
return Ok(false);
|
||||
return false;
|
||||
}
|
||||
Ok(mode & Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0)
|
||||
mode & Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
|
||||
+26
-21
@@ -637,13 +637,13 @@ pub(super) mod _os {
|
||||
#[pyclass(flags(DISALLOW_INSTANTIATION), with(Representable))]
|
||||
impl DirEntry {
|
||||
#[pygetset]
|
||||
fn name(&self, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(self.mode.process_path(&self.file_name, vm))
|
||||
fn name(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.mode.process_path(&self.file_name, vm)
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn path(&self, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(self.mode.process_path(&self.pathval, vm))
|
||||
fn path(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.mode.process_path(&self.pathval, vm)
|
||||
}
|
||||
|
||||
/// Build the DirFd to use for stat calls.
|
||||
@@ -837,30 +837,30 @@ pub(super) mod _os {
|
||||
|
||||
#[cfg(unix)]
|
||||
#[pymethod]
|
||||
fn inode(&self, _vm: &VirtualMachine) -> PyResult<u64> {
|
||||
Ok(self.ino.load())
|
||||
fn inode(&self, _vm: &VirtualMachine) -> u64 {
|
||||
self.ino.load()
|
||||
}
|
||||
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
#[pymethod]
|
||||
fn inode(&self, _vm: &VirtualMachine) -> PyResult<Option<u64>> {
|
||||
Ok(self.ino.load())
|
||||
fn inode(&self, _vm: &VirtualMachine) -> Option<u64> {
|
||||
self.ino.load()
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[pymethod]
|
||||
const fn is_junction(&self, _vm: &VirtualMachine) -> PyResult<bool> {
|
||||
Ok(false)
|
||||
const fn is_junction(&self, _vm: &VirtualMachine) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[pymethod]
|
||||
fn is_junction(&self, _vm: &VirtualMachine) -> PyResult<bool> {
|
||||
Ok(junction::exists(self.pathval.clone()).unwrap_or(false))
|
||||
fn is_junction(&self, _vm: &VirtualMachine) -> bool {
|
||||
junction::exists(self.pathval.clone()).unwrap_or(false)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __fspath__(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn __fspath__(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.path(vm)
|
||||
}
|
||||
|
||||
@@ -941,6 +941,7 @@ pub(super) mod _os {
|
||||
Err(vm.new_type_error("cannot pickle 'ScandirIterator' object"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Destructor for ScandirIterator {
|
||||
fn del(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
// Emit ResourceWarning if the iterator is not yet exhausted/closed
|
||||
@@ -956,7 +957,9 @@ pub(super) mod _os {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl SelfIter for ScandirIterator {}
|
||||
|
||||
impl IterNext for ScandirIterator {
|
||||
fn next(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
let entryref: &mut Option<fs::ReadDir> = &mut zelf.entries.write();
|
||||
@@ -1904,6 +1907,10 @@ pub(super) mod _os {
|
||||
#[pyclass(with(PyStructSequence))]
|
||||
impl PyTimesResult {}
|
||||
|
||||
#[allow(
|
||||
clippy::unnecessary_wraps,
|
||||
reason = "Can return an error on some platforms"
|
||||
)]
|
||||
#[cfg(all(any(unix, windows), not(target_os = "redox")))]
|
||||
#[pyfunction]
|
||||
fn times(vm: &VirtualMachine) -> PyResult {
|
||||
@@ -2107,14 +2114,14 @@ pub(super) mod _os {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn device_encoding(fd: i32, _vm: &VirtualMachine) -> PyResult<Option<String>> {
|
||||
fn device_encoding(fd: i32, _vm: &VirtualMachine) -> Option<String> {
|
||||
if !isatty(fd) {
|
||||
return Ok(None);
|
||||
return None;
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
any(target_os = "android", target_os = "redox") => {
|
||||
Ok(Some("UTF-8".to_owned()))
|
||||
Some("UTF-8".to_owned())
|
||||
}
|
||||
windows => {
|
||||
use windows_sys::Win32::System::Console;
|
||||
@@ -2124,19 +2131,17 @@ pub(super) mod _os {
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
Ok(Some(format!("cp{cp}")))
|
||||
Some(format!("cp{cp}"))
|
||||
}
|
||||
_ => {
|
||||
let encoding = unsafe {
|
||||
Some(unsafe {
|
||||
let encoding = libc::nl_langinfo(libc::CODESET);
|
||||
if encoding.is_null() || encoding.read() == b'\0' as libc::c_char {
|
||||
"UTF-8".to_owned()
|
||||
} else {
|
||||
core::ffi::CStr::from_ptr(encoding).to_string_lossy().into_owned()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(encoding))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ mod pwd {
|
||||
// TODO: maybe merge this functionality into nix?
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[pyfunction]
|
||||
fn getpwall(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
||||
fn getpwall(vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
// setpwent, getpwent, etc are not thread safe. Could use fgetpwent_r, but this is easier
|
||||
static GETPWALL: parking_lot::Mutex<()> = parking_lot::Mutex::new(());
|
||||
let _guard = GETPWALL.lock();
|
||||
@@ -112,6 +112,6 @@ mod pwd {
|
||||
}
|
||||
unsafe { libc::endpwent() };
|
||||
|
||||
Ok(list)
|
||||
list
|
||||
}
|
||||
}
|
||||
+13
-15
@@ -85,16 +85,15 @@ pub mod sys {
|
||||
#[pyclass]
|
||||
impl BootstrapStderr {
|
||||
#[pymethod]
|
||||
fn write(&self, s: PyStrRef) -> PyResult<usize> {
|
||||
fn write(&self, s: PyStrRef) -> usize {
|
||||
let bytes = s.as_bytes();
|
||||
let _ = std::io::stderr().write_all(bytes);
|
||||
Ok(bytes.len())
|
||||
bytes.len()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn flush(&self) -> PyResult<()> {
|
||||
fn flush(&self) {
|
||||
let _ = std::io::stderr().flush();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -997,14 +996,14 @@ pub mod sys {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn _getframemodulename(depth: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult {
|
||||
fn _getframemodulename(depth: OptionalArg<usize>, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let depth = depth.into_option().unwrap_or(0);
|
||||
|
||||
// Get the frame at the specified depth
|
||||
let func_obj = {
|
||||
let frames = vm.frames.borrow();
|
||||
if depth >= frames.len() {
|
||||
return Ok(vm.ctx.none());
|
||||
return vm.ctx.none();
|
||||
}
|
||||
let idx = frames.len() - depth - 1;
|
||||
// SAFETY: the FrameRef is alive on the call stack while it's in the Vec
|
||||
@@ -1014,15 +1013,14 @@ pub mod sys {
|
||||
|
||||
// If the frame has a function object, return its __module__ attribute
|
||||
if let Some(func_obj) = func_obj {
|
||||
match func_obj.get_attr(identifier!(vm, __module__), vm) {
|
||||
Ok(module) => Ok(module),
|
||||
Err(_) => {
|
||||
func_obj
|
||||
.get_attr(identifier!(vm, __module__), vm)
|
||||
.unwrap_or_else(
|
||||
// CPython clears the error and returns None
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
}
|
||||
|_| vm.ctx.none(),
|
||||
)
|
||||
} else {
|
||||
Ok(vm.ctx.none())
|
||||
vm.ctx.none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,8 +1073,8 @@ pub mod sys {
|
||||
/// Stub for non-threading builds - returns empty dict
|
||||
#[cfg(not(feature = "threading"))]
|
||||
#[pyfunction]
|
||||
fn _current_frames(vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
Ok(vm.ctx.new_dict())
|
||||
fn _current_frames(vm: &VirtualMachine) -> PyDictRef {
|
||||
vm.ctx.new_dict()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
@@ -1002,6 +1002,7 @@ pub mod decl {
|
||||
#[allow(unused_imports)]
|
||||
use super::platform::*;
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(
|
||||
vm: &VirtualMachine,
|
||||
module: &Py<crate::builtins::PyModule>,
|
||||
|
||||
@@ -173,40 +173,46 @@ pub(crate) mod typevar {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn evaluate_bound(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn evaluate_bound(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
if !vm.is_none(&self.evaluate_bound) {
|
||||
return Ok(self.evaluate_bound.clone());
|
||||
return self.evaluate_bound.clone();
|
||||
}
|
||||
|
||||
let bound = self.bound.lock();
|
||||
if !vm.is_none(&bound) {
|
||||
return Ok(const_evaluator_alloc(bound.clone(), vm));
|
||||
return const_evaluator_alloc(bound.clone(), vm);
|
||||
}
|
||||
Ok(vm.ctx.none())
|
||||
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn evaluate_constraints(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn evaluate_constraints(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
if !vm.is_none(&self.evaluate_constraints) {
|
||||
return Ok(self.evaluate_constraints.clone());
|
||||
return self.evaluate_constraints.clone();
|
||||
}
|
||||
|
||||
let constraints = self.constraints.lock();
|
||||
if !vm.is_none(&constraints) {
|
||||
return Ok(const_evaluator_alloc(constraints.clone(), vm));
|
||||
return const_evaluator_alloc(constraints.clone(), vm);
|
||||
}
|
||||
Ok(vm.ctx.none())
|
||||
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn evaluate_default(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn evaluate_default(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let evaluator = self.evaluate_default.lock().clone();
|
||||
if !vm.is_none(&evaluator) {
|
||||
return Ok(evaluator);
|
||||
return evaluator;
|
||||
}
|
||||
|
||||
let default_value = self.default_value.lock().clone();
|
||||
if !default_value.is(&vm.ctx.typing_no_default) {
|
||||
return Ok(const_evaluator_alloc(default_value, vm));
|
||||
return const_evaluator_alloc(default_value, vm);
|
||||
}
|
||||
Ok(vm.ctx.none())
|
||||
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -480,21 +486,21 @@ pub(crate) mod typevar {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn args(zelf: crate::PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
fn args(zelf: crate::PyRef<Self>, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let self_obj: PyObjectRef = zelf.into();
|
||||
let psa = ParamSpecArgs {
|
||||
__origin__: self_obj,
|
||||
};
|
||||
Ok(psa.into_ref(&vm.ctx).into())
|
||||
psa.into_ref(&vm.ctx).into()
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn kwargs(zelf: crate::PyRef<Self>, vm: &VirtualMachine) -> PyResult {
|
||||
fn kwargs(zelf: crate::PyRef<Self>, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let self_obj: PyObjectRef = zelf.into();
|
||||
let psk = ParamSpecKwargs {
|
||||
__origin__: self_obj,
|
||||
};
|
||||
Ok(psk.into_ref(&vm.ctx).into())
|
||||
psk.into_ref(&vm.ctx).into()
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
@@ -539,21 +545,23 @@ pub(crate) mod typevar {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn evaluate_default(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn evaluate_default(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let evaluator = self.evaluate_default.lock().clone();
|
||||
if !vm.is_none(&evaluator) {
|
||||
return Ok(evaluator);
|
||||
return evaluator;
|
||||
}
|
||||
|
||||
let default_value = self.default_value.lock().clone();
|
||||
if !default_value.is(&vm.ctx.typing_no_default) {
|
||||
return Ok(const_evaluator_alloc(default_value, vm));
|
||||
return const_evaluator_alloc(default_value, vm);
|
||||
}
|
||||
Ok(vm.ctx.none())
|
||||
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(&self) -> PyResult {
|
||||
Ok(self.name.clone())
|
||||
fn __reduce__(&self) -> PyObjectRef {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -748,16 +756,18 @@ pub(crate) mod typevar {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn evaluate_default(&self, vm: &VirtualMachine) -> PyResult {
|
||||
fn evaluate_default(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let evaluator = self.evaluate_default.lock().clone();
|
||||
if !vm.is_none(&evaluator) {
|
||||
return Ok(evaluator);
|
||||
return evaluator;
|
||||
}
|
||||
|
||||
let default_value = self.default_value.lock().clone();
|
||||
if !default_value.is(&vm.ctx.typing_no_default) {
|
||||
return Ok(const_evaluator_alloc(default_value, vm));
|
||||
return const_evaluator_alloc(default_value, vm);
|
||||
}
|
||||
Ok(vm.ctx.none())
|
||||
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
|
||||
@@ -195,15 +195,15 @@ mod winreg {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn Detach(&self) -> PyResult<usize> {
|
||||
fn Detach(&self) -> usize {
|
||||
// Atomically swap the handle with null and return the old value
|
||||
let old_hkey = self.hkey.swap(core::ptr::null_mut());
|
||||
Ok(old_hkey as usize)
|
||||
old_hkey as usize
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __enter__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
Ok(zelf)
|
||||
fn __enter__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
|
||||
zelf
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -216,8 +216,8 @@ mod winreg {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __str__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyRef<PyStr>> {
|
||||
Ok(vm.ctx.new_str(format!("<PyHkey:{:p}>", zelf.hkey.load())))
|
||||
fn __str__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyRef<PyStr> {
|
||||
vm.ctx.new_str(format!("<PyHkey:{:p}>", zelf.hkey.load()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -579,7 +579,8 @@ fn bool_wrapper(num: PyNumber<'_>, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
Ok(crate::builtins::bool_::get_value(&result))
|
||||
}
|
||||
|
||||
// PyObject_SelfIter in CPython
|
||||
/// PyObject_SelfIter in CPython
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
const fn self_iter(zelf: PyObjectRef, _vm: &VirtualMachine) -> PyResult {
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
@@ -846,7 +846,7 @@ impl VirtualMachine {
|
||||
let codec_info = getregentry.call((), self)?;
|
||||
self.state
|
||||
.codec_registry
|
||||
.register_manual("ascii", codec_info.try_into_value(self)?)?;
|
||||
.register_manual("ascii", codec_info.try_into_value(self)?);
|
||||
|
||||
// Register utf-8 encoding (also as "utf8" alias since normalize_encoding_name
|
||||
// maps "utf-8" → "utf_8" but leaves "utf8" as-is)
|
||||
@@ -857,10 +857,10 @@ impl VirtualMachine {
|
||||
let utf8_codec: crate::codecs::PyCodec = codec_info.try_into_value(self)?;
|
||||
self.state
|
||||
.codec_registry
|
||||
.register_manual("utf-8", utf8_codec.clone())?;
|
||||
.register_manual("utf-8", utf8_codec.clone());
|
||||
self.state
|
||||
.codec_registry
|
||||
.register_manual("utf8", utf8_codec)?;
|
||||
.register_manual("utf8", utf8_codec);
|
||||
|
||||
// Register latin-1 / iso8859-1 aliases needed very early for stdio
|
||||
// bootstrap (e.g. PYTHONIOENCODING=latin-1).
|
||||
@@ -873,7 +873,7 @@ impl VirtualMachine {
|
||||
for name in ["latin-1", "latin_1", "latin1", "iso8859-1", "iso8859_1"] {
|
||||
self.state
|
||||
.codec_registry
|
||||
.register_manual(name, latin1_codec.clone())?;
|
||||
.register_manual(name, latin1_codec.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
+21
-21
@@ -114,7 +114,7 @@ fn get_warnings_attr(
|
||||
vm: &VirtualMachine,
|
||||
attr_name: &'static PyStrInterned,
|
||||
try_import: bool,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
) -> Option<PyObjectRef> {
|
||||
let module = if try_import
|
||||
&& !vm
|
||||
.state
|
||||
@@ -123,38 +123,36 @@ fn get_warnings_attr(
|
||||
{
|
||||
match vm.import("warnings", 0) {
|
||||
Ok(module) => module,
|
||||
Err(_) => return Ok(None),
|
||||
Err(_) => return None,
|
||||
}
|
||||
} else {
|
||||
match vm.sys_module.get_attr(identifier!(vm, modules), vm) {
|
||||
Ok(modules) => match modules.get_item(vm.ctx.intern_str("warnings"), vm) {
|
||||
Ok(module) => module,
|
||||
Err(_) => return Ok(None),
|
||||
Err(_) => return None,
|
||||
},
|
||||
Err(_) => return Ok(None),
|
||||
Err(_) => return None,
|
||||
}
|
||||
};
|
||||
match module.get_attr(attr_name, vm) {
|
||||
Ok(attr) => Ok(Some(attr)),
|
||||
Err(_) => Ok(None),
|
||||
}
|
||||
|
||||
module.get_attr(attr_name, vm).ok()
|
||||
}
|
||||
|
||||
/// Get the warnings filters list from sys.modules['warnings'].filters,
|
||||
/// falling back to vm.state.warnings.filters.
|
||||
fn get_warnings_filters(vm: &VirtualMachine) -> PyResult<PyListRef> {
|
||||
if let Some(filters_obj) = get_warnings_attr(vm, identifier!(&vm.ctx, filters), false)?
|
||||
fn get_warnings_filters(vm: &VirtualMachine) -> PyListRef {
|
||||
if let Some(filters_obj) = get_warnings_attr(vm, identifier!(&vm.ctx, filters), false)
|
||||
&& let Ok(filters) = filters_obj.try_into_value::<PyListRef>(vm)
|
||||
{
|
||||
return Ok(filters);
|
||||
return filters;
|
||||
}
|
||||
Ok(vm.state.warnings.filters.clone())
|
||||
vm.state.warnings.filters.clone()
|
||||
}
|
||||
|
||||
/// Get the default action from sys.modules['warnings']._defaultaction,
|
||||
/// falling back to vm.state.warnings.default_action.
|
||||
fn get_default_action(vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
if let Some(action) = get_warnings_attr(vm, identifier!(&vm.ctx, defaultaction), false)? {
|
||||
if let Some(action) = get_warnings_attr(vm, identifier!(&vm.ctx, defaultaction), false) {
|
||||
if !action.class().is(vm.ctx.types.str_type) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"_warnings.defaultaction must be a string, not '{}'",
|
||||
@@ -169,7 +167,7 @@ fn get_default_action(vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
/// Get the once registry from sys.modules['warnings']._onceregistry,
|
||||
/// falling back to vm.state.warnings.once_registry.
|
||||
fn get_once_registry(vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
if let Some(registry) = get_warnings_attr(vm, identifier!(&vm.ctx, onceregistry), false)? {
|
||||
if let Some(registry) = get_warnings_attr(vm, identifier!(&vm.ctx, onceregistry), false) {
|
||||
if !registry.class().is(vm.ctx.types.dict_type) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"_warnings.onceregistry must be a dict, not '{}'",
|
||||
@@ -265,7 +263,7 @@ fn get_filter(
|
||||
module: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let filters = get_warnings_filters(vm)?;
|
||||
let filters = get_warnings_filters(vm);
|
||||
|
||||
// filters could change while we are iterating over it.
|
||||
// Re-check list length each iteration (matches C behavior).
|
||||
@@ -463,15 +461,17 @@ fn call_show_warning(
|
||||
source: Option<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
let Some(show_fn) =
|
||||
get_warnings_attr(vm, identifier!(&vm.ctx, _showwarnmsg), source.is_some())?
|
||||
let Some(show_fn) = get_warnings_attr(vm, identifier!(&vm.ctx, _showwarnmsg), source.is_some())
|
||||
else {
|
||||
return show_warning(filename, lineno, text, category, source_line, vm);
|
||||
show_warning(filename, lineno, text, category, source_line, vm);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if !show_fn.is_callable() {
|
||||
return Err(vm.new_type_error("warnings._showwarnmsg() must be set to a callable"));
|
||||
}
|
||||
let Some(warnmsg_cls) = get_warnings_attr(vm, identifier!(&vm.ctx, WarningMessage), false)?
|
||||
|
||||
let Some(warnmsg_cls) = get_warnings_attr(vm, identifier!(&vm.ctx, WarningMessage), false)
|
||||
else {
|
||||
return Err(vm.new_runtime_error("unable to get warnings.WarningMessage"));
|
||||
};
|
||||
@@ -488,6 +488,7 @@ fn call_show_warning(
|
||||
],
|
||||
vm,
|
||||
)?;
|
||||
|
||||
show_fn.call((msg,), vm)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -499,7 +500,7 @@ fn show_warning(
|
||||
category: PyTypeRef,
|
||||
_source_line: Option<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
) {
|
||||
let stderr = crate::stdlib::sys::PyStderr(vm);
|
||||
writeln!(
|
||||
stderr,
|
||||
@@ -509,7 +510,6 @@ fn show_warning(
|
||||
category.name(),
|
||||
text
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if a frame's filename starts with any of the given prefixes.
|
||||
|
||||
@@ -26,6 +26,7 @@ mod _window {
|
||||
use super::{js_module, wasm_builtins};
|
||||
use rustpython_vm::{Py, PyPayload, PyResult, VirtualMachine, builtins::PyModule};
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
__module_exec(vm, module);
|
||||
extend_module!(vm, module, {
|
||||
|
||||
Reference in new issue
Block a user