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: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ jobs:

- name: Check whats_left is not broken
shell: bash
run: python -I scripts/whats_left.py --rustpython target/release/rustpython
run: python -I scripts/whats_left.py --signature --rustpython target/release/rustpython

clippy:
# Named after the matrix entry rather than left to be named for it: a
Expand Down
87 changes: 72 additions & 15 deletions crates/stdlib/src/pystruct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) mod _struct {
buffer::{FormatSpec, new_struct_error, struct_error_type},
builtins::{PyBytes, PyStr, PyStrRef, PyTupleRef, PyType, PyTypeRef},
common::{lock::PyRwLock, rc::PyRc},
function::{ArgBytesLike, ArgMemoryBuffer, FuncArgs, PosArgs},
function::{ArgBytesLike, ArgMemoryBuffer, FuncArgs, NameValues, PosArgs},
match_class,
protocol::PyIterReturn,
stdlib::_warnings,
Expand Down Expand Up @@ -122,21 +122,25 @@ pub(crate) mod _struct {
}

#[pyfunction]
fn pack(fmt: IntoStructFormatBytes, args: PosArgs, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
fmt.cached_format_spec(vm)?.pack(args.into_vec(), vm)
fn pack(
format: IntoStructFormatBytes,
values: PosArgs<PyObjectRef, NameValues>,
vm: &VirtualMachine,
) -> PyResult<Vec<u8>> {
format.cached_format_spec(vm)?.pack(values.into_vec(), vm)
}

#[pyfunction]
fn pack_into(
fmt: IntoStructFormatBytes,
format: IntoStructFormatBytes,
buffer: ArgMemoryBuffer,
offset: isize,
args: PosArgs,
values: PosArgs<PyObjectRef, NameValues>,
vm: &VirtualMachine,
) -> PyResult<()> {
let format_spec = fmt.cached_format_spec(vm)?;
let format_spec = format.cached_format_spec(vm)?;
let offset = get_buffer_offset(buffer.len(), offset, format_spec.size, true, vm)?;
buffer.with_ref(|data| format_spec.pack_into(&mut data[offset..], args.into_vec(), vm))
buffer.with_ref(|data| format_spec.pack_into(&mut data[offset..], values.into_vec(), vm))
}

#[pyfunction]
Expand Down Expand Up @@ -381,19 +385,24 @@ pub(crate) mod _struct {
}

impl Initializer for PyStruct {
type Args = FuncArgs;
type Args = StructArgs;

fn init(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
let format = zelf.inner.read().as_ref().map(|inner| inner.format.clone());
fn slot_init(zelf: &PyObject, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
let zelf = zelf.try_to_ref::<Self>(vm)?;
if !zelf.init_called.load()
&& Self::uses_struct_init(zelf.class(), vm)
&& format.is_some()
&& zelf.inner.read().is_some()
{
// The implicit __init__ must not reinterpret a custom __new__'s arguments.
zelf.init_called.store(true);
return Ok(());
}
let args = StructArgs::bind(args, vm)?;
Self::init(zelf, args, vm)
}

fn init(zelf: &Py<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
let format = zelf.inner.read().as_ref().map(|inner| inner.format.clone());
if let Some(format) = format {
if Self::same_format(&format, &args.format) {
zelf.init_called.store(true);
Expand Down Expand Up @@ -445,24 +454,28 @@ pub(crate) mod _struct {
}

#[pymethod]
fn pack(zelf: &Py<Self>, args: PosArgs, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
zelf.ready(vm)?.spec.pack(args.into_vec(), vm)
fn pack(
zelf: &Py<Self>,
values: PosArgs<PyObjectRef, NameValues>,
vm: &VirtualMachine,
) -> PyResult<Vec<u8>> {
zelf.ready(vm)?.spec.pack(values.into_vec(), vm)
}

#[pymethod]
fn pack_into(
zelf: &Py<Self>,
buffer: ArgMemoryBuffer,
offset: isize,
args: PosArgs,
values: PosArgs<PyObjectRef, NameValues>,
vm: &VirtualMachine,
) -> PyResult<()> {
let inner = zelf.ready(vm)?;
let offset = get_buffer_offset(buffer.len(), offset, inner.spec.size, true, vm)?;
buffer.with_ref(|data| {
inner
.spec
.pack_into(&mut data[offset..], args.into_vec(), vm)
.pack_into(&mut data[offset..], values.into_vec(), vm)
})
}

Expand Down Expand Up @@ -527,4 +540,48 @@ pub(crate) mod _struct {
fn error_type(vm: &VirtualMachine) -> PyTypeRef {
struct_error_type(vm).to_owned()
}

#[cfg(test)]
mod tests {
use super::*;
use crate::vm::class::PyClassImpl;

#[test]
fn struct_constructor_signature_metadata() {
assert!(
<PyStruct as PyClassImpl>::INTERNAL_DOC
.text
.unwrap()
.starts_with("Struct(format)\n--\n\n")
);
}

#[test]
fn struct_pack_signature_metadata() {
for (methods, name, expected) in [
(METHOD_DEFS, "pack", "pack($module, format, /, *values)"),
(
METHOD_DEFS,
"pack_into",
"pack_into($module, format, buffer, offset, /, *values)",
),
(
<PyStruct as PyClassImpl>::METHOD_DEFS,
"pack",
"pack($self, /, *values)",
),
(
<PyStruct as PyClassImpl>::METHOD_DEFS,
"pack_into",
"pack_into($self, buffer, offset, /, *values)",
),
] {
let method = methods.iter().find(|method| method.name == name).unwrap();
assert_eq!(
method.doc.unwrap().split_once("\n--\n\n").unwrap().0,
expected
);
}
}
}
}
1 change: 1 addition & 0 deletions crates/vm/src/function/argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ arg_name! {
NameIterables = "iterables",
NameKeywords = "keywords",
NameFields = "fields",
NameValues = "values",
}

#[derive(Clone, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/src/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod time;
pub use argument::{
ArgumentError, Callee, FromArgOptional, FromArgs, FuncArgs, IntoFuncArgs, KwArgs, KwArgsMap,
NameArgs, NameChanges, NameCoordinates, NameExcInfo, NameFields, NameIntegers, NameIterables,
NameKeywords, NameKwargs, NameKwds, NameKws, NameObjs, NameOthers, OptionalArg,
NameKeywords, NameKwargs, NameKwds, NameKws, NameObjs, NameOthers, NameValues, OptionalArg,
OptionalArgDefault, OptionalOption, PosArgs, PositionalIterable,
};
pub(crate) use argument::{
Expand Down
39 changes: 36 additions & 3 deletions crates/vm/src/stdlib/_sre.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ mod _sre {
common::wtf8::{Wtf8, Wtf8Buf, wtf8_concat},
common::{ascii, hash::PyHash},
convert::ToPyObject,
function::{ArgCallable, OptionalArg, PosArgs, PyComparisonValue},
function::{ArgCallable, DefaultRepr, OptionalArg, PosArgs, PyComparisonValue},
protocol::{BufferFlags, PyBuffer, PyCallable, PyMappingMethods},
stdlib::sys,
types::{AsMapping, Comparable, Hashable, Representable},
Expand Down Expand Up @@ -344,9 +344,15 @@ mod _sre {

/// A position in the searched string, taken as a Py_ssize_t; a negative
/// one means the start of the string.
#[derive(Clone, Copy, Default)]
#[derive(Clone, Copy)]
struct StringPos(usize);

impl StringPos {
const fn py_default(self) -> DefaultRepr {
DefaultRepr::Int(self.0 as i128)
}
}

impl TryFromObject for StringPos {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let pos: isize = obj.try_into_value(vm)?;
Expand All @@ -357,7 +363,7 @@ mod _sre {
#[derive(FromArgs)]
struct StringArgs {
string: PyObjectRef,
#[pyarg(any, default)]
#[pyarg(any, default = StringPos(0))]
pos: StringPos,
// Platform ssize maximum, shown as sys.maxsize.
#[pyarg(any, default = StringPos(sys::MAXSIZE as usize), py_default = "sys.maxsize")]
Expand Down Expand Up @@ -1257,4 +1263,31 @@ mod _sre {
)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::class::PyClassImpl;

#[test]
fn pattern_position_signature_metadata() {
for name in [
"findall",
"finditer",
"fullmatch",
"match",
"prefixmatch",
"scanner",
"search",
] {
let method = <Pattern as PyClassImpl>::METHOD_DEFS
.iter()
.find(|method| method.name == name)
.unwrap();
let expected =
format!("{name}($self, /, string, pos=0, endpos=sys.maxsize)\n--\n\n");
assert!(method.doc.unwrap().starts_with(&expected), "{name}");
}
}
}
}
Loading