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
16 changes: 8 additions & 8 deletions crates/stdlib/src/_asyncio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ pub(crate) mod _asyncio {
vm: &VirtualMachine,
) -> PyResult<()> {
if zelf.fut_loop.read().is_some() {
return Err(vm.new_runtime_error(format!(
"{} object is already initialized",
zelf.class().fully_qualified_name(vm)?
return Err(vm.new_runtime_error(wtf8_concat!(
zelf.class().fully_qualified_name(vm)?,
" object is already initialized"
)));
}

Expand Down Expand Up @@ -1201,9 +1201,9 @@ pub(crate) mod _asyncio {
impl PyTask {
fn py_init(zelf: &Py<Self>, args: TaskInitArgs, vm: &VirtualMachine) -> PyResult<()> {
if zelf.base.fut_loop.read().is_some() {
return Err(vm.new_runtime_error(format!(
"{} object is already initialized",
zelf.class().fully_qualified_name(vm)?
return Err(vm.new_runtime_error(wtf8_concat!(
zelf.class().fully_qualified_name(vm)?,
" object is already initialized"
)));
}

Expand Down Expand Up @@ -1245,8 +1245,8 @@ pub(crate) mod _asyncio {
if !c.class().is(PyContext::class(&vm.ctx)) {
zelf.task_log_destroy_pending
.store(false, Ordering::Relaxed);
return Err(vm.new_type_error(format!(
"a contextvars.Context was expected, got {}",
return Err(vm.new_type_error(wtf8_concat!(
"a contextvars.Context was expected, got ",
c.class().fully_qualified_name(vm)?
)));
}
Expand Down
23 changes: 14 additions & 9 deletions crates/stdlib/src/_zoneinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) use _zoneinfo::module_def;
#[pymodule]
mod _zoneinfo {
use alloc::collections::VecDeque;
use rustpython_common::wtf8::{Wtf8Buf, wtf8_concat};
use std::collections::HashMap;

use crate::_datetime::{PyTzInfo, datetime_type, timedelta_from_seconds};
Expand Down Expand Up @@ -1002,10 +1003,14 @@ mod _zoneinfo {
vm: &VirtualMachine,
) -> PyResult {
let qual = instance.class().fully_qualified_name(vm)?;
let key_repr = key.repr(vm)?.to_string_lossy().into_owned();
Err(vm.new_runtime_error(format!(
"Unexpected instance of {qual} in {} weak cache for key {key_repr}",
cls.name()
let key_repr = key.repr(vm)?.as_wtf8().to_owned();
Err(vm.new_runtime_error(wtf8_concat!(
"Unexpected instance of ",
qual,
" in ",
&*cls.name(),
" weak cache for key ",
key_repr
)))
}

Expand Down Expand Up @@ -1217,14 +1222,14 @@ mod _zoneinfo {
}

impl Representable for ZoneInfo {
fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
fn repr_wtf8(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
let name = zelf.class().fully_qualified_name(vm)?;
if vm.is_none(&zelf.key) {
let file = zelf.file_repr.as_deref().unwrap_or("");
return Ok(format!("{name}.from_file({file})"));
return Ok(wtf8_concat!(name, ".from_file(", file, ")"));
}
let key = zelf.key.repr(vm)?.to_string_lossy().into_owned();
Ok(format!("{name}(key={key})"))
let key = zelf.key.repr(vm)?.as_wtf8().to_owned();
Ok(wtf8_concat!(name, "(key=", key, ")"))
}
}

Expand Down Expand Up @@ -1414,7 +1419,7 @@ mod _zoneinfo {
zelf.key.class().slot_name()
)));
}
Ok(vm.ctx.new_str(Self::repr_str(zelf, vm)?))
Self::repr(zelf, vm)
}
}

Expand Down
13 changes: 6 additions & 7 deletions crates/stdlib/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mod _socket {
types::{Constructor, DefaultConstructor, Destructor, Initializer, Representable},
utils::ToCString,
};
use rustpython_common::wtf8::wtf8_concat;
use rustpython_host_env::os::ErrorExt;
#[cfg(any(unix, windows))]
use rustpython_host_env::socket as host_socket;
Expand Down Expand Up @@ -2819,9 +2820,10 @@ mod _socket {
Value::Buffer(buffer)
} else {
return Err(vm
.new_type_error(format!(
"socket option should be int, bytes-like object or None (got {})",
value.class().fully_qualified_name(vm)?
.new_type_error(wtf8_concat!(
"socket option should be int, bytes-like object or None (got ",
value.class().fully_qualified_name(vm)?,
")"
))
.into());
}
Expand All @@ -2836,10 +2838,7 @@ mod _socket {
}
(Some(value), OptionalArg::Present(_)) => {
return Err(vm
.new_type_error(format!(
"setsockopt() only takes 4 arguments when the third argument is None (got {})",
value.class().fully_qualified_name(vm)?
))
.new_type_error(wtf8_concat!("setsockopt() only takes 4 arguments when the third argument is None (got ", value.class().fully_qualified_name(vm)?, ")"))
.into());
}
};
Expand Down
5 changes: 3 additions & 2 deletions crates/vm/src/builtins/asyncgenerator.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use rustpython_common::wtf8::wtf8_concat;
// spell-checker: ignore AGEN

use super::{PyCode, PyGenericAlias, PyStrRef, PyType, PyTypeRef};
Expand Down Expand Up @@ -740,8 +741,8 @@ impl PyAnextAwaitable {
let coro_await = vm.call_method(&awaitable, "__await__", ())?;
// Check that __await__ returned an iterator
if !PyIter::check(&coro_await) {
return Err(vm.new_type_error(format!(
"anext_awaitable.__await__() must return an iterable, not {}",
return Err(vm.new_type_error(wtf8_concat!(
"anext_awaitable.__await__() must return an iterable, not ",
coro_await.class().fully_qualified_name(vm)?
)));
}
Expand Down
17 changes: 9 additions & 8 deletions crates/vm/src/builtins/complex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use core::ptr::NonNull;
use num_complex::Complex64;
use num_traits::Zero;
use rustpython_common::hash;
use rustpython_common::wtf8::wtf8_concat;

#[pyclass(module = false, name = "complex")]
#[derive(Debug, Copy, Clone, PartialEq)]
Expand Down Expand Up @@ -434,17 +435,17 @@ impl Constructor for PyComplex {
&& original_real.downcast_ref::<Self>().is_none()
&& !has_real_number_conversion(&original_real)
{
return Err(vm.new_type_error(format!(
"complex() argument 'real' must be a real number, not {}",
return Err(vm.new_type_error(wtf8_concat!(
"complex() argument 'real' must be a real number, not ",
original_real.class().fully_qualified_name(vm)?
)));
}
if let OptionalArg::Present(imag) = &args.imag
&& imag.downcast_ref::<Self>().is_none()
&& !has_real_number_conversion(imag)
{
return Err(vm.new_type_error(format!(
"complex() argument 'imag' must be a real number, not {}",
return Err(vm.new_type_error(wtf8_concat!(
"complex() argument 'imag' must be a real number, not ",
imag.class().fully_qualified_name(vm)?
)));
}
Expand All @@ -463,8 +464,8 @@ impl Constructor for PyComplex {
if !has_real_number_conversion(&original_real) {
_warnings::warn(
vm.ctx.exceptions.deprecation_warning,
format!(
"complex() argument 'real' must be a real number, not {}",
wtf8_concat!(
"complex() argument 'real' must be a real number, not ",
original_real.class().fully_qualified_name(vm)?
),
1,
Expand All @@ -484,8 +485,8 @@ impl Constructor for PyComplex {
if let Some(value) = obj.downcast_ref::<Self>() {
_warnings::warn(
vm.ctx.exceptions.deprecation_warning,
format!(
"complex() argument 'imag' must be a real number, not {}",
wtf8_concat!(
"complex() argument 'imag' must be a real number, not ",
obj.class().fully_qualified_name(vm)?
),
1,
Expand Down
9 changes: 6 additions & 3 deletions crates/vm/src/builtins/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
};
use core::mem::{align_of, size_of};
use rustpython_common::lock::PyRwLock;
use rustpython_common::wtf8::wtf8_concat;

#[derive(Debug)]
pub struct PyDescriptor {
Expand Down Expand Up @@ -1134,10 +1135,12 @@ fn member_get_one(
MemberKind::ObjectEx => match obj.get_slot(offset) {
Some(value) => value,
None => {
return Err(vm.new_attribute_error(format!(
"'{}' object has no attribute '{}'",
return Err(vm.new_attribute_error(wtf8_concat!(
"'",
obj.class().fully_qualified_name(vm)?,
member.name
"' object has no attribute '",
member.name,
"'"
)));
}
},
Expand Down
11 changes: 9 additions & 2 deletions crates/vm/src/builtins/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use core::ptr::NonNull;
use rustpython_common::atomic::{Ordering, PyAtomic, Radium};
use rustpython_common::lock::PyMutex;
use rustpython_common::wtf8::Wtf8Buf;
use rustpython_common::wtf8::wtf8_concat;

pub(crate) type DictContentType = dict_inner::Dict;

Expand All @@ -51,8 +52,14 @@ pub(crate) fn key_hash<K: DictKey + ?Sized>(
[arg] => arg.str(vm)?,
_ => args.as_object().str(vm)?,
};
Err(vm.new_type_error(format!(
"cannot use '{name}' as a {mapping_name} key ({message})"
Err(vm.new_type_error(wtf8_concat!(
"cannot use '",
name,
"' as a ",
mapping_name,
" key (",
message.as_wtf8(),
")"
)))
}
result => result,
Expand Down
4 changes: 2 additions & 2 deletions crates/vm/src/builtins/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,8 +1122,8 @@ impl Py<PyFunction> {
let ann_dict = match result?.downcast::<crate::builtins::PyDict>() {
Ok(dict) => dict,
Err(obj) => {
return Err(vm.new_type_error(format!(
"__annotate__() must return a dict, not {}",
return Err(vm.new_type_error(wtf8_concat!(
"__annotate__() must return a dict, not ",
obj.class().fully_qualified_name(vm)?
)));
}
Expand Down
8 changes: 6 additions & 2 deletions crates/vm/src/builtins/genericalias.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use rustpython_common::wtf8::wtf8_concat;
// spell-checker:ignore iparam gaiterobject
use crate::common::lock::{LazyLock, PyMutex};

Expand Down Expand Up @@ -607,8 +608,11 @@ pub(crate) fn subs_parameters(
Err(_) => {
let arg_type = arg.class().fully_qualified_name(vm)?;
let substituted_type = substituted_arg.class().fully_qualified_name(vm)?;
return Err(vm.new_type_error(format!(
"expected __typing_subst__ of {arg_type} objects to return a tuple, not {substituted_type}",
return Err(vm.new_type_error(wtf8_concat!(
"expected __typing_subst__ of ",
arg_type,
" objects to return a tuple, not ",
substituted_type
)));
}
};
Expand Down
7 changes: 5 additions & 2 deletions crates/vm/src/builtins/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use core::ptr::NonNull;
use malachite_bigint::{BigInt, Sign};
use num_integer::{ExtendedGcd, Integer};
use num_traits::{One, Pow, PrimInt, Signed, ToPrimitive, Zero};
use rustpython_common::wtf8::wtf8_concat;

#[pyclass(module = false, name = "int")]
#[derive(Debug)]
Expand Down Expand Up @@ -652,8 +653,10 @@ impl Py<PyInt> {
args.bytes.class().fully_qualified_name(vm),
result.class().fully_qualified_name(vm),
) {
(Ok(source), Ok(result)) => vm.new_type_error(format!(
"{source}.__bytes__() must return a bytes, not {result}"
(Ok(source), Ok(result)) => vm.new_type_error(wtf8_concat!(
source,
".__bytes__() must return a bytes, not ",
result
)),
(Err(error), _) | (_, Err(error)) => error,
}
Expand Down
6 changes: 5 additions & 1 deletion crates/vm/src/builtins/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
import::{get_spec_file_origin, is_possibly_shadowing_path, is_stdlib_module_name},
types::{GetAttr, Initializer, Representable},
};
use rustpython_common::wtf8::wtf8_concat;

#[pyclass(module = false, name = "module")]
#[derive(Debug)]
Expand Down Expand Up @@ -442,7 +443,10 @@ impl PyModule {
let result = annotate.call((1i32,), vm)?;
if !result.downcastable::<PyDict>() {
let error = result.class().fully_qualified_name(vm).map(|name| {
vm.new_type_error(format!("__annotate__() must return a dict, not {name}"))
vm.new_type_error(wtf8_concat!(
"__annotate__() must return a dict, not ",
name
))
});
drop(annotate);
drop(result);
Expand Down
35 changes: 21 additions & 14 deletions crates/vm/src/builtins/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use core::{
use indexmap::{IndexMap, map::Entry};
use itertools::Itertools;
use num_traits::ToPrimitive;
use rustpython_common::wtf8::Wtf8;
use rustpython_common::wtf8::{Wtf8, Wtf8Buf, wtf8_concat};
use std::collections::HashSet;

pub(crate) type PyTypeTupleRef = PyRef<PyTuple<PyTypeRef>>;
Expand Down Expand Up @@ -1717,19 +1717,26 @@ impl PyType {

/// The type's fully qualified name, the way the `%T` format code prints it:
/// `module.qualname`, with a `builtins` or `__main__` module left off.
pub fn fully_qualified_name(&self, vm: &VirtualMachine) -> PyResult<String> {
pub fn fully_qualified_name(&self, vm: &VirtualMachine) -> PyResult<Wtf8Buf> {
// Static types use tp_name verbatim, including its module prefix.
if !self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
return Ok((&*self.slot_name()).into());
}
// Read the stored metadata, bypassing metaclass and str-subclass hooks.
// A Python name can contain lone surrogates, so neither this helper nor
// its callers may pass it through Rust's UTF-8 Display formatting.
let qualname = self.__qualname__(vm);
let qualname = qualname
.downcast_ref::<PyStr>()
.and_then(|qualname| qualname.to_str())
.map_or_else(|| self.name().to_string(), str::to_owned);
.expect("type qualname is a string")
.as_wtf8();
let module = self.__module__(vm)?;
Ok(
match module.downcast_ref::<PyStr>().and_then(|m| m.to_str()) {
Some("builtins" | "__main__") | None => qualname,
Some(module) => format!("{module}.{qualname}"),
},
)
match module.downcast_ref::<PyStr>() {
Some(module) if !matches!(module.to_str(), Some("builtins" | "__main__")) => {
Ok(wtf8_concat!(module.as_wtf8(), '.', qualname))
}
_ => Ok(qualname.to_owned()),
}
}

pub fn name(&self) -> BorrowedValue<'_, str> {
Expand Down Expand Up @@ -1962,8 +1969,8 @@ impl Constructor for PyType {
let (name, bases, dict, kwargs): (PyStrRef, PyTupleRef, PyObjectRef, KwArgs) =
args.clone().bind_for(vm, Self::NAME)?;
let Some(dict) = PyAnyDict::from_object(&dict) else {
return Err(vm.new_type_error(format!(
"type.__new__() argument 3 must be dict or frozendict, not {}",
return Err(vm.new_type_error(wtf8_concat!(
"type.__new__() argument 3 must be dict or frozendict, not ",
dict.class().fully_qualified_name(vm)?
)));
};
Expand Down Expand Up @@ -3136,8 +3143,8 @@ impl Py<PyType> {
// Call __annotate__(1) where 1 is FORMAT_VALUE
let result = annotate.call((1i32,), vm)?;
if !result.downcastable::<PyDict>() {
return Err(vm.new_type_error(format!(
"__annotate__() must return a dict, not {}",
return Err(vm.new_type_error(wtf8_concat!(
"__annotate__() must return a dict, not ",
result.class().fully_qualified_name(vm)?
)));
}
Expand Down
Loading
Loading