Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
flamescope = { version = "0.1.2", optional = true }

rustls = { workspace = true, optional = true }
rustls-graviola = { workspace = true, optional = true }

Check warning on line 52 in Cargo.toml

View workflow job for this annotation

GitHub Actions / cargo shear

shear/misplaced_optional_dependency

misplaced optional dependency `rustls-graviola` (remove the `optional` flag and move to `[dev-dependencies]`)

[target.'cfg(windows)'.dependencies]
libc = { workspace = true }
Expand Down Expand Up @@ -373,6 +373,7 @@
or_fun_call = "warn"
redundant_clone = "warn"
search_is_some = "warn"
significant_drop_in_scrutinee = "warn"
single_option_map = "warn"
trait_duplication_in_bounds = "warn"
unused_peekable = "warn"
Expand All @@ -386,6 +387,7 @@
collapsible_else_if = "warn"
comparison_chain = "warn"
duration_suboptimal_units = "warn"
explicit_deref_methods = "warn"
explicit_into_iter_loop = "warn"
explicit_iter_loop = "warn"
filter_map_next = "warn"
Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl<T: ?Sized> Deref for BorrowedValue<'_, T> {

impl fmt::Display for BorrowedValue<'_, str> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.deref(), f)
fmt::Display::fmt(&**self, f)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ impl FormatSpec {
cmp::max(0, (w as i32) - (num_chars as i32) - (sign_str.len() as i32))
});

let magnitude_str = magnitude_str.deref();
let magnitude_str = &**magnitude_str;
match align {
FormatAlign::Left => format!(
"{}{}{}",
Expand Down
49 changes: 30 additions & 19 deletions crates/stdlib/src/_asyncio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,12 @@ pub(crate) mod _asyncio {
}
FutureState::Finished => {
self.fut_log_tb.store(false, Ordering::Relaxed);
if let Some(exc) = self.fut_exception.read().clone() {
let fut_exception = self.fut_exception.read().clone();
if let Some(exc) = fut_exception {
let exc: PyBaseExceptionRef = exc.downcast().unwrap();
// Restore the original traceback to prevent traceback accumulation
if let Some(tb) = self.fut_exception_tb.read().clone() {
let fut_exception_tb = self.fut_exception_tb.read().clone();
if let Some(tb) = fut_exception_tb {
let _ = exc.set___traceback__(tb, vm);
}
Err(exc)
Expand Down Expand Up @@ -612,7 +614,8 @@ pub(crate) mod _asyncio {
fn _callbacks(&self, vm: &VirtualMachine) -> PyObjectRef {
let mut result = Vec::new();

if let Some(cb0) = self.fut_callback0.read().clone() {
let fut_callback0 = self.fut_callback0.read().clone();
if let Some(cb0) = fut_callback0 {
let ctx0 = self
.fut_context0
.read()
Expand All @@ -621,7 +624,8 @@ pub(crate) mod _asyncio {
result.push(vm.ctx.new_tuple(vec![cb0, ctx0]).into());
}

if let Some(callbacks) = self.fut_callbacks.read().clone() {
let fut_callbacks = self.fut_callbacks.read().clone();
if let Some(callbacks) = fut_callbacks {
let list: PyListRef = callbacks.downcast().unwrap();
for item in list.borrow_vec().iter() {
result.push(item.clone());
Expand Down Expand Up @@ -792,16 +796,12 @@ pub(crate) mod _asyncio {
return Ok(());
}

let exc = zelf.fut_exception.read().clone();
let exc = match exc {
Some(e) => e,
None => return Ok(()),
let Some(exc) = zelf.fut_exception.read().clone() else {
return Ok(());
};

let loop_obj = zelf.fut_loop.read().clone();
let loop_obj = match loop_obj {
Some(l) => l,
None => return Ok(()),
let Some(loop_obj) = zelf.fut_loop.read().clone() else {
return Ok(());
};

// Create context dict for call_exception_handler
Expand All @@ -816,7 +816,8 @@ pub(crate) mod _asyncio {
context.set_item(vm.ctx.intern_str("exception"), exc, vm)?;
context.set_item(vm.ctx.intern_str("future"), zelf.to_owned().into(), vm)?;

if let Some(tb) = zelf.fut_source_tb.read().clone() {
let fut_source_tb = zelf.fut_source_tb.read().clone();
if let Some(tb) = fut_source_tb {
context.set_item(vm.ctx.intern_str("source_traceback"), tb, vm)?;
}

Expand Down Expand Up @@ -1248,12 +1249,15 @@ pub(crate) mod _asyncio {
FutureState::Cancelled => Err(self.make_cancelled_error_impl(vm)),
FutureState::Finished => {
self.base.fut_log_tb.store(false, Ordering::Relaxed);
if let Some(exc) = self.base.fut_exception.read().clone() {
let fut_exception = self.base.fut_exception.read().clone();
if let Some(exc) = fut_exception {
let exc: PyBaseExceptionRef = exc.downcast().unwrap();
// Restore the original traceback to prevent traceback accumulation
if let Some(tb) = self.base.fut_exception_tb.read().clone() {
let fut_exception_tb = self.base.fut_exception_tb.read().clone();
if let Some(tb) = fut_exception_tb {
let _ = exc.set___traceback__(tb, vm);
}

Err(exc)
} else {
Ok(self
Expand Down Expand Up @@ -1517,7 +1521,8 @@ pub(crate) mod _asyncio {

let msg_value = args.msg.flatten();

if let Some(fut_waiter) = self.task_fut_waiter.read().clone() {
let task_fut_waiter = self.task_fut_waiter.read().clone();
if let Some(fut_waiter) = task_fut_waiter {
// Call cancel with msg=msg keyword argument
let cancel_args = if let Some(ref m) = msg_value {
FuncArgs::new(
Expand Down Expand Up @@ -1795,7 +1800,9 @@ pub(crate) mod _asyncio {
#[pygetset]
fn _callbacks(&self, vm: &VirtualMachine) -> PyObjectRef {
let mut result: Vec<PyObjectRef> = Vec::new();
if let Some(cb) = self.base.fut_callback0.read().clone() {

let fut_callback0 = self.base.fut_callback0.read().clone();
if let Some(cb) = fut_callback0 {
let ctx = self
.base
.fut_context0
Expand All @@ -1804,13 +1811,15 @@ pub(crate) mod _asyncio {
.unwrap_or_else(|| vm.ctx.none());
result.push(vm.ctx.new_tuple(vec![cb, ctx]).into());
}

if let Some(callbacks) = self.base.fut_callbacks.read().clone()
&& let Ok(list) = callbacks.downcast::<PyList>()
{
for item in list.borrow_vec().iter() {
result.push(item.clone());
}
}

// Return None if no callbacks
if result.is_empty() {
vm.ctx.none()
Expand Down Expand Up @@ -1859,7 +1868,8 @@ pub(crate) mod _asyncio {
)?;
context.set_item(vm.ctx.intern_str("task"), zelf.to_owned().into(), vm)?;

if let Some(tb) = zelf.base.fut_source_tb.read().clone() {
let fut_source_tb = zelf.base.fut_source_tb.read().clone();
if let Some(tb) = fut_source_tb {
context.set_item(vm.ctx.intern_str("source_traceback"), tb, vm)?;
}

Expand Down Expand Up @@ -1896,7 +1906,8 @@ pub(crate) mod _asyncio {
context.set_item(vm.ctx.intern_str("exception"), exc, vm)?;
context.set_item(vm.ctx.intern_str("future"), zelf.to_owned().into(), vm)?;

if let Some(tb) = zelf.base.fut_source_tb.read().clone() {
let fut_source_tb = zelf.base.fut_source_tb.read().clone();
if let Some(tb) = fut_source_tb {
context.set_item(vm.ctx.intern_str("source_traceback"), tb, vm)?;
}

Expand Down
3 changes: 2 additions & 1 deletion crates/stdlib/src/_sqlite3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,8 @@ mod _sqlite3 {

#[pygetset]
fn autocommit(&self, vm: &VirtualMachine) -> PyObjectRef {
match *self.autocommit.lock() {
let mode = *self.autocommit.lock();
match mode {
AutocommitMode::Enabled => vm.ctx.true_value.clone().into(),
AutocommitMode::Disabled => vm.ctx.false_value.clone().into(),
AutocommitMode::Legacy => vm.ctx.new_int(LEGACY_TRANSACTION_CONTROL).into(),
Expand Down
12 changes: 8 additions & 4 deletions crates/stdlib/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,8 @@ pub mod array {

if let OptionalArg::Present(init) = init {
if let Some(init) = init.downcast_ref::<Self>() {
match (spec, init.read().typecode()) {
let value = init.read().typecode();
match (spec, value) {
(spec, ch) if spec == ch => array.frombytes(&init.get_bytes()),
(spec, 'u') => {
return Err(vm.new_type_error(format!(
Expand Down Expand Up @@ -1406,12 +1407,15 @@ pub mod array {
}

impl SelfIter for PyArrayIter {}

impl IterNext for PyArrayIter {
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
zelf.internal.lock().next(|array, pos| {
Ok(match array.read().get(pos, vm) {
Some(item) => PyIterReturn::Return(item?),
None => PyIterReturn::StopIteration(None),
let value = array.read().get(pos, vm);
Ok(if let Some(item) = value {
PyIterReturn::Return(item?)
} else {
PyIterReturn::StopIteration(None)
})
})
}
Expand Down
3 changes: 2 additions & 1 deletion crates/stdlib/src/ssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3413,7 +3413,8 @@ mod _ssl {
// Initialize connection if not already done
if conn_guard.is_none() {
// Check for pending context change (from SNI callback)
if let Some(new_ctx) = self.pending_context.write().take() {
let pending_context = self.pending_context.write().take();
if let Some(new_ctx) = pending_context {
*self.context.write() = new_ctx;
}

Expand Down
8 changes: 5 additions & 3 deletions crates/vm/src/builtins/classmethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,11 @@ impl PyClassMethod {

#[pygetset]
fn __isabstractmethod__(&self, vm: &VirtualMachine) -> PyObjectRef {
match vm.get_attribute_opt(self.callable.lock().clone(), "__isabstractmethod__") {
Ok(Some(is_abstract)) => is_abstract,
_ => vm.ctx.new_bool(false).into(),
let callable = self.callable.lock().clone();
if let Ok(Some(is_abstract)) = vm.get_attribute_opt(callable, "__isabstractmethod__") {
is_abstract
} else {
vm.ctx.new_bool(false).into()
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/vm/src/builtins/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,13 +398,13 @@ impl PyList {
let (mut elements, version_before) = {
let mut guard = self.elements.write();
let version_before = self.mutation_counter.load(Ordering::Relaxed);
(core::mem::take(guard.deref_mut()), version_before)
(core::mem::take(&mut *guard), version_before)
};
let res = do_sort(vm, &mut elements, options.key, options.reverse);
let mutated = {
let mut guard = self.elements.write();
let mutated = self.mutation_counter.load(Ordering::Relaxed) != version_before;
core::mem::swap(guard.deref_mut(), &mut elements);
core::mem::swap(&mut *guard, &mut elements);
mutated
};
res?;
Expand Down
24 changes: 16 additions & 8 deletions crates/vm/src/builtins/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,12 @@ impl GetDescriptor for PyProperty {
) -> PyResult {
let (zelf, obj) = Self::_unwrap(&zelf_obj, obj, vm)?;
if vm.is_none(&obj) {
Ok(zelf_obj)
} else if let Some(getter) = zelf.getter.read().clone() {
// Clone and release lock before calling Python code to prevent deadlock
return Ok(zelf_obj);
}

// Clone and release lock before calling Python code to prevent deadlock
let value = zelf.getter.read().clone();
if let Some(getter) = value {
getter.call((obj,), vm)
} else {
let error_msg = zelf.format_property_error(&obj, "getter", vm)?;
Expand All @@ -74,7 +77,8 @@ impl PyProperty {
// Returns the name if available, None if not found, or propagates errors
fn get_property_name(&self, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
// First check if name was set via __set_name__
if let Some(name) = self.name.read().clone() {
let value = self.name.read().clone();
if let Some(name) = value {
return Ok(Some(name));
}

Expand Down Expand Up @@ -110,7 +114,8 @@ impl PyProperty {
match value {
PySetterValue::Assign(value) => {
// Clone and release lock before calling Python code to prevent deadlock
if let Some(setter) = zelf.setter.read().clone() {
let set = zelf.setter.read().clone();
if let Some(setter) = set {
setter.call((obj, value), vm).map(drop)
} else {
let error_msg = zelf.format_property_error(&obj, "setter", vm)?;
Expand All @@ -119,7 +124,8 @@ impl PyProperty {
}
PySetterValue::Delete => {
// Clone and release lock before calling Python code to prevent deadlock
if let Some(deleter) = zelf.deleter.read().clone() {
let del = zelf.deleter.read().clone();
if let Some(deleter) = del {
deleter.call((obj,), vm).map(drop)
} else {
let error_msg = zelf.format_property_error(&obj, "deleter", vm)?;
Expand Down Expand Up @@ -224,7 +230,8 @@ impl PyProperty {
Self::init(new_prop_ref.clone(), args, vm)?;

// Copy the name if it exists
if let Some(name) = zelf.name.read().clone() {
let value = zelf.name.read().clone();
if let Some(name) = value {
*new_prop_ref.name.write() = Some(name);
}

Expand Down Expand Up @@ -296,7 +303,8 @@ impl PyProperty {
#[pygetset(setter)]
fn set___isabstractmethod__(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
// Clone and release lock before calling Python code to prevent deadlock
if let Some(getter) = self.getter.read().clone() {
let maybe_getter = self.getter.read().clone();
if let Some(getter) = maybe_getter {
getter.set_attr("__isabstractmethod__", value, vm)?;
}
Ok(())
Expand Down
17 changes: 11 additions & 6 deletions crates/vm/src/builtins/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ use super::{
IterStatus, PositionIterInternal, PyDict, PyDictRef, PyGenericAlias, PyTupleRef, PyType,
PyTypeRef, builtins_iter,
};
use crate::common::lock::LazyLock;
use crate::{
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
atomic_func,
class::PyClassImpl,
common::{ascii, hash::PyHash, lock::PyMutex, rc::PyRc, wtf8::Wtf8Buf},
common::{
ascii,
hash::PyHash,
lock::{LazyLock, PyMutex},
rc::PyRc,
wtf8::Wtf8Buf,
},
convert::ToPyResult,
dict_inner::{self, DictSize},
function::{ArgIterable, FuncArgs, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue},
Expand All @@ -24,9 +29,7 @@ use crate::{
utils::collection_repr,
vm::VirtualMachine,
};
use alloc::fmt;
use core::borrow::Borrow;
use core::ops::Deref;
use core::{borrow::Borrow, fmt};
use rustpython_common::{
atomic::{Ordering, PyAtomic, Radium},
hash,
Expand Down Expand Up @@ -924,10 +927,12 @@ impl Representable for PySet {
fn repr_wtf8(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
let class = zelf.class();
let borrowed_name = class.name();
let class_name = borrowed_name.deref();
let class_name = &*borrowed_name;

if zelf.inner.len() == 0 {
return Ok(Wtf8Buf::from(format!("{class_name}()")));
}

if let Some(_guard) = ReprGuard::enter(vm, zelf.as_object()) {
let name = (class_name != "set").then_some(class_name);
zelf.inner.repr(name, vm)
Expand Down
9 changes: 6 additions & 3 deletions crates/vm/src/builtins/staticmethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,12 @@ impl PyStaticMethod {

#[pygetset]
fn __isabstractmethod__(&self, vm: &VirtualMachine) -> PyObjectRef {
match vm.get_attribute_opt(self.callable.lock().clone(), "__isabstractmethod__") {
Ok(Some(is_abstract)) => is_abstract,
_ => vm.ctx.new_bool(false).into(),
let callable = self.callable.lock().clone();

if let Ok(Some(is_abstract)) = vm.get_attribute_opt(callable, "__isabstractmethod__") {
is_abstract
} else {
vm.ctx.new_bool(false).into()
}
}

Expand Down
Loading
Loading