mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Report every generated __text_signature__, and keep it out of __doc__ (#8614)
* Strip the signature prefix from builtin __doc__
A function's signature and its documentation share one string, separated
by `\n--\n\n`, as in CPython. __text_signature__ read the front of it,
but __doc__ returned the whole thing:
>>> len.__doc__
'len(obj, /)\n--\n\nReturn the number of items in a container.' # was
'Return the number of items in a container.' # now
44 of the 46 builtin functions leaked the prefix.
get_doc_from_internal_doc already stripped it but was reachable only from
PyType.__doc__. Split it the way CPython does, into doc_without_signature
(_PyType_DocWithoutSignature) and a wrapper mapping an empty result to
None (_PyType_GetDocFromInternalDoc), and call it from PyNativeFunction
and PyMethodDescriptor as well.
Assisted-by: Claude Code:claude-opus-5
* Terminate a generated __text_signature__ that carries no documentation
A signature and its documentation share one string, separated by
`\n--\n\n`, and readers find the signature by searching for that marker.
A #[pyfunction] with no doc comment stored the bare signature, which no
reader could parse:
>>> time.clock_getres.__doc__
'clock_getres(clk_id, /)'
>>> time.clock_getres.__text_signature__
None
Emit the marker in that case too, as Argument Clinic does for an
undocumented function. 136 of the 915 functions reachable from the
importable modules were affected.
__doc__ now reports None for them, matching CPython, because nothing
follows the marker.
Assisted-by: Claude Code:claude-opus-5
* Report a __text_signature__ for every method
A #[pymethod] built its doc only when the method carried a doc comment,
so one without a comment dropped the generated signature too:
>>> list.append.__text_signature__
None
Build it from either part, as #[pyfunction] does. All 1101 method
descriptors reachable from the builtin types now report a signature, up
from 1, and 713 of the 1030 that CPython also describes match it exactly.
A method that takes its receiver as an ordinary first argument instead of
`&self` reported that argument by name, so binding the method could not
drop it:
>>> inspect.signature([].__dir__)
(obj, /) # was
() # now
Mark it $self, or $type for a classmethod, as CPython does. 310 methods
were affected.
test_unbound_builtin_method_noargs and test_bound_builtin_method_noargs
pass now.
Assisted-by: Claude Code:claude-opus-5
* Drop the expectedFailure on test_simple_completion
rlcompleter closes the parenthesis for a callable whose signature takes
no parameters, and leaves it open when the signature cannot be read:
def _callable_postfix(self, val, word):
if callable(val):
word += "("
try:
if not inspect.signature(val).parameters:
word += ")"
except ValueError:
pass
os.getpid reports `()` since the generated signature carries the `--`
terminator, so completing `os.getpid` yields `os.getpid()` and the test
passes.
Assisted-by: Claude Code:claude-opus-5
* Name every #[pymethod] receiver zelf
A method that needs an owned handle cannot take `&self`, so it takes the
receiver as its first argument and names it `zelf`, `self` being a Rust
keyword. 24 of the 163 such methods named it something else: `instance`
(11), `obj` (4), `exc` (3), `_self` (3), `_instance` (2).
Rename them. The generated signature is unaffected either way, since the
macro marks the receiver by position rather than by name.
Assisted-by: Claude Code:claude-opus-5
* Drop the unreachable zelf name check in func_sig
The receiver is now marked by position, so the name it carries no longer
matters, and no path reaches this check with an argument named zelf:
- a #[pymethod] or #[pyclassmethod] without a `&self` receiver has its
first argument replaced by the marker before the name is read
- a `&self` receiver is handled as syn::FnArg::Receiver
- a #[pymethod(raw)] is passed to static_raw_func, whose PyNativeFn bound
fixes its signature to (&VirtualMachine, FuncArgs)
- no #[pystaticmethod] or #[pyfunction] names an argument zelf
- #[pymember], #[pygetset] and #[pyslot] never reach func_sig
Every generated signature is byte for byte identical without it.
Assisted-by: Claude Code:claude-opus-5
* Keep the argument bundle when marking the receiver
A #[pyclassmethod] that takes FuncArgs receives the class inside the
bundle along with every other argument, but the marker was spent on the
bundle and the arguments went unreported:
>>> object.__subclasshook__.__text_signature__
'($type, /)' # was, claims it takes nothing
'($type, *args, **kwargs)' # now
Report both, the shape CPython uses for __new__. Two methods take their
arguments this way, __subclasshook__ on object and on type.
Assisted-by: Claude Code:claude-opus-5
This commit is contained in:
1 parent
5b1a1c08d7
commit
d1bbf4bc1a
14 files changed
+115
-78
No files matched your search
Vendored
-2
@@ -1597,12 +1597,10 @@ class TestDescriptions(unittest.TestCase):
|
||||
self.assertEqual(self._get_summary_line(_stat.S_IMODE),
|
||||
"S_IMODE(object, /)")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_unbound_builtin_method_noargs(self):
|
||||
self.assertEqual(self._get_summary_line(str.lower),
|
||||
"lower(self, /) unbound builtins.str method")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_bound_builtin_method_noargs(self):
|
||||
self.assertEqual(self._get_summary_line(''.lower),
|
||||
"lower() method of builtins.str instance")
|
||||
|
||||
Vendored
-1
@@ -858,7 +858,6 @@ class TestPyReplCompleter(TestCase):
|
||||
reader = ReadlineAlikeReader(console=console, config=config)
|
||||
return reader
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@patch("rlcompleter._readline_available", False)
|
||||
def test_simple_completion(self):
|
||||
events = code_to_events("os.getpid\t\n")
|
||||
|
||||
@@ -1077,16 +1077,25 @@ where
|
||||
}
|
||||
|
||||
let raw = item_meta.raw()?;
|
||||
let sig_doc = text_signature(func.sig(), &py_name);
|
||||
let has_receiver = func
|
||||
.sig()
|
||||
.inputs
|
||||
.iter()
|
||||
.any(|arg| matches!(arg, syn::FnArg::Receiver(_)));
|
||||
let drop_first_typed = match self.inner.attr_name {
|
||||
AttrName::Method | AttrName::ClassMethod if !has_receiver && !raw => 1,
|
||||
_ => 0,
|
||||
// Without a `&self` receiver the first argument is the one the call
|
||||
// binds to, and CPython names it $self for a method and $type for a
|
||||
// classmethod.
|
||||
let implicit_self = if has_receiver || raw {
|
||||
None
|
||||
} else {
|
||||
match self.inner.attr_name {
|
||||
AttrName::Method => Some("$self"),
|
||||
AttrName::ClassMethod => Some("$type"),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
let drop_first_typed = usize::from(implicit_self.is_some());
|
||||
let sig_doc = text_signature(func.sig(), &py_name, implicit_self);
|
||||
let call_flags = infer_native_call_flags(func.sig(), drop_first_typed);
|
||||
|
||||
// Add #[allow(non_snake_case)] for setter methods like set___name__
|
||||
@@ -1096,10 +1105,11 @@ where
|
||||
args.attrs.push(allow_attr);
|
||||
}
|
||||
|
||||
let doc = args.attrs.doc().map(|doc| match &sig_doc {
|
||||
Some(sig_doc) => format_doc(sig_doc, &doc),
|
||||
None => doc,
|
||||
});
|
||||
let doc = match (sig_doc, args.attrs.doc()) {
|
||||
(Some(sig_doc), Some(doc)) => Some(format_doc(&sig_doc, &doc)),
|
||||
(Some(sig_doc), None) => Some(format_doc(&sig_doc, "")),
|
||||
(None, doc) => doc,
|
||||
};
|
||||
args.context.method_items.add_item(MethodNurseryItem {
|
||||
py_name,
|
||||
cfgs: args.cfgs.to_vec(),
|
||||
|
||||
@@ -664,7 +664,7 @@ impl ModuleItem for FunctionItem {
|
||||
let item_meta = SimpleItemMeta::from_attr(ident.clone(), &item_attr)?;
|
||||
|
||||
let py_name = item_meta.simple_name()?;
|
||||
let sig_doc = text_signature(func.sig(), &py_name);
|
||||
let sig_doc = text_signature(func.sig(), &py_name, None);
|
||||
|
||||
let module = args.module_name();
|
||||
// TODO: doc must exist at least one of code or CPython
|
||||
@@ -675,7 +675,7 @@ impl ModuleItem for FunctionItem {
|
||||
});
|
||||
let doc = match (sig_doc, doc) {
|
||||
(Some(sig_doc), Some(doc)) => Some(format_doc(&sig_doc, &doc)),
|
||||
(Some(sig_doc), None) => Some(sig_doc),
|
||||
(Some(sig_doc), None) => Some(format_doc(&sig_doc, "")),
|
||||
(None, doc) => doc,
|
||||
};
|
||||
|
||||
|
||||
@@ -735,8 +735,12 @@ where
|
||||
//
|
||||
// Unlike CPython, a `#[pyfunction]` doesn't take the module as an argument yet,
|
||||
// so there's no module to mark with `$module`.
|
||||
pub(crate) fn text_signature(sig: &Signature, name: &str) -> Option<String> {
|
||||
let signature = func_sig(sig)?;
|
||||
pub(crate) fn text_signature(
|
||||
sig: &Signature,
|
||||
name: &str,
|
||||
implicit_self: Option<&str>,
|
||||
) -> Option<String> {
|
||||
let signature = func_sig(sig, implicit_self)?;
|
||||
// Arguments bind through `FuncArgs::take_positional`, which never consults
|
||||
// the keyword map, so they are positional-only. `*args`/`**kwargs` cannot be
|
||||
// followed by `/`, and an empty parameter list has nothing to mark.
|
||||
@@ -821,7 +825,10 @@ pub(crate) fn infer_native_call_flags(sig: &Signature, drop_first_typed: usize)
|
||||
|
||||
/// Returns None when an argument has no name to report, in which case no
|
||||
/// signature can be generated for the function.
|
||||
fn func_sig(sig: &Signature) -> Option<String> {
|
||||
///
|
||||
/// `implicit_self` is the marker to report for a first argument that the call
|
||||
/// binds to without a `&self` receiver.
|
||||
fn func_sig(sig: &Signature, mut implicit_self: Option<&str>) -> Option<String> {
|
||||
let mut params = Vec::new();
|
||||
for arg in &sig.inputs {
|
||||
let arg = match arg {
|
||||
@@ -834,12 +841,19 @@ fn func_sig(sig: &Signature) -> Option<String> {
|
||||
let ty = arg.ty.as_ref();
|
||||
let ty = quote!(#ty).to_string();
|
||||
if ty == "FuncArgs" {
|
||||
// The bundle carries the receiver along with everything else, so
|
||||
// report both rather than spending the marker on it.
|
||||
params.extend(implicit_self.take().map(str::to_owned));
|
||||
params.push("*args, **kwargs".to_owned());
|
||||
continue;
|
||||
}
|
||||
if ty.starts_with('&') && ty.ends_with("VirtualMachine") {
|
||||
continue;
|
||||
}
|
||||
if let Some(marker) = implicit_self.take() {
|
||||
params.push(marker.to_owned());
|
||||
continue;
|
||||
}
|
||||
// An argument bound by a destructuring pattern, e.g.
|
||||
// `fn round(RoundArgs { number, ndigits }: RoundArgs, ..)`, has no name
|
||||
// to report. Stringifying the pattern would emit Rust syntax, which
|
||||
@@ -848,10 +862,6 @@ fn func_sig(sig: &Signature) -> Option<String> {
|
||||
return None;
|
||||
};
|
||||
let ident = pat.ident.to_string();
|
||||
if ident == "zelf" {
|
||||
params.push("$self".to_owned());
|
||||
continue;
|
||||
}
|
||||
if ident == "vm" {
|
||||
unreachable!("type &VirtualMachine(`{ty}`) must be filtered already");
|
||||
}
|
||||
|
||||
@@ -42,17 +42,17 @@ pub(crate) mod ssl_error {
|
||||
impl PySSLError {
|
||||
// Returns strerror attribute if available, otherwise str(args)
|
||||
#[pymethod]
|
||||
fn __str__(exc: &Py<PyBaseException>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
fn __str__(zelf: &Py<PyBaseException>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
|
||||
use crate::vm::AsObject;
|
||||
// Try to get strerror attribute first (OSError compatibility)
|
||||
if let Ok(strerror) = exc.as_object().get_attr("strerror", vm)
|
||||
if let Ok(strerror) = zelf.as_object().get_attr("strerror", vm)
|
||||
&& !vm.is_none(&strerror)
|
||||
{
|
||||
return strerror.str(vm);
|
||||
}
|
||||
|
||||
// Otherwise return str(args)
|
||||
let args = exc.args();
|
||||
let args = zelf.args();
|
||||
if args.len() == 1 {
|
||||
args.as_slice()[0].str(vm)
|
||||
} else {
|
||||
|
||||
@@ -106,8 +106,8 @@ impl Constructor for PyBool {
|
||||
#[pyclass(with(Constructor, AsNumber, Representable), flags(_MATCH_SELF))]
|
||||
impl PyBool {
|
||||
#[pymethod]
|
||||
fn __format__(obj: PyObjectRef, spec: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let new_bool = obj.try_to_bool(vm)?;
|
||||
fn __format__(zelf: PyObjectRef, spec: PyUtf8StrRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let new_bool = zelf.try_to_bool(vm)?;
|
||||
FormatSpec::parse(spec.as_str())
|
||||
.and_then(|format_spec| format_spec.format_bool(new_bool))
|
||||
.map_err(|err| err.into_pyexception(vm))
|
||||
|
||||
@@ -164,9 +164,11 @@ impl PyNativeFunction {
|
||||
Ok(qualname)
|
||||
}
|
||||
|
||||
// meth_get__doc__ in CPython
|
||||
#[pygetset]
|
||||
fn __doc__(zelf: NativeFunctionOrMethod) -> Option<&'static str> {
|
||||
zelf.0.value.doc
|
||||
let doc = zelf.0.value.doc?;
|
||||
type_::get_doc_from_internal_doc(zelf.0.value.name, doc)
|
||||
}
|
||||
|
||||
// meth_get__self__ in CPython
|
||||
|
||||
@@ -134,8 +134,9 @@ impl PyMethodDescriptor {
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
const fn __doc__(&self) -> Option<&'static str> {
|
||||
self.method.doc
|
||||
fn __doc__(&self) -> Option<&'static str> {
|
||||
let doc = self.method.doc?;
|
||||
type_::get_doc_from_internal_doc(self.method.name, doc)
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
|
||||
@@ -397,8 +397,8 @@ impl PyBaseObject {
|
||||
fn __init_subclass__(_cls: PyTypeRef) {}
|
||||
|
||||
#[pymethod]
|
||||
pub fn __dir__(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyList> {
|
||||
obj.dir(vm)
|
||||
pub fn __dir__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyList> {
|
||||
zelf.dir(vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -468,22 +468,22 @@ impl PyBaseObject {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
common_reduce(obj, 0, vm)
|
||||
fn __reduce__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
common_reduce(zelf, 0, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce_ex__(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
|
||||
fn __reduce_ex__(zelf: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult {
|
||||
let __reduce__ = identifier!(vm, __reduce__);
|
||||
if let Some(reduce) = vm.get_attribute_opt(obj.clone(), __reduce__)? {
|
||||
if let Some(reduce) = vm.get_attribute_opt(zelf.clone(), __reduce__)? {
|
||||
let object_reduce = vm.ctx.types.object_type.get_attr(__reduce__).unwrap();
|
||||
let typ_obj: PyObjectRef = obj.class().to_owned().into();
|
||||
let typ_obj: PyObjectRef = zelf.class().to_owned().into();
|
||||
let class_reduce = typ_obj.get_attr(__reduce__, vm)?;
|
||||
if !class_reduce.is(&object_reduce) {
|
||||
return reduce.call((), vm);
|
||||
}
|
||||
}
|
||||
common_reduce(obj, proto, vm)
|
||||
common_reduce(zelf, proto, vm)
|
||||
}
|
||||
|
||||
#[expect(clippy::unnecessary_wraps, reason = "Needs to comply with a signature")]
|
||||
|
||||
@@ -2758,9 +2758,8 @@ pub(crate) fn get_text_signature_from_internal_doc<'a>(
|
||||
find_signature(name, internal_doc).and_then(get_signature)
|
||||
}
|
||||
|
||||
// _PyType_GetDocFromInternalDoc in CPython
|
||||
fn get_doc_from_internal_doc<'a>(name: &str, internal_doc: &'a str) -> &'a str {
|
||||
// Similar to CPython's _PyType_DocWithoutSignature
|
||||
// _PyType_DocWithoutSignature in CPython
|
||||
fn doc_without_signature<'a>(name: &str, internal_doc: &'a str) -> &'a str {
|
||||
// If the doc starts with the type name and a '(', it's a signature
|
||||
if let Some(doc_without_sig) = find_signature(name, internal_doc) {
|
||||
// Find where the signature ends
|
||||
@@ -2774,6 +2773,12 @@ fn get_doc_from_internal_doc<'a>(name: &str, internal_doc: &'a str) -> &'a str {
|
||||
internal_doc
|
||||
}
|
||||
|
||||
// _PyType_GetDocFromInternalDoc in CPython
|
||||
pub(crate) fn get_doc_from_internal_doc<'a>(name: &str, internal_doc: &'a str) -> Option<&'a str> {
|
||||
let doc = doc_without_signature(name, internal_doc);
|
||||
(!doc.is_empty()).then_some(doc)
|
||||
}
|
||||
|
||||
impl Initializer for PyType {
|
||||
type Args = FuncArgs;
|
||||
|
||||
@@ -2862,7 +2867,7 @@ impl Py<PyType> {
|
||||
{
|
||||
// Process internal doc, removing signature if present
|
||||
let doc_str = get_doc_from_internal_doc(&self.name(), internal_doc);
|
||||
return Ok(vm.ctx.new_str(doc_str).into());
|
||||
return Ok(doc_str.map_or_else(|| vm.ctx.none(), |doc| vm.ctx.new_str(doc).into()));
|
||||
}
|
||||
|
||||
// Check if there's a __doc__ in THIS type's dict only (not MRO)
|
||||
|
||||
@@ -1916,11 +1916,11 @@ pub(super) mod types {
|
||||
#[pyexception(with(Initializer))]
|
||||
impl PyImportError {
|
||||
#[pymethod]
|
||||
fn __reduce__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let obj = exc.as_object().to_owned();
|
||||
let args: PyObjectRef = match exc.get_arg(0) {
|
||||
fn __reduce__(zelf: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let obj = zelf.as_object().to_owned();
|
||||
let args: PyObjectRef = match zelf.get_arg(0) {
|
||||
Some(arg) => vm.new_tuple((arg,)).into(),
|
||||
None => exc.args().into(),
|
||||
None => zelf.args().into(),
|
||||
};
|
||||
let mut result: Vec<PyObjectRef> = vec![obj.class().to_owned().into(), args];
|
||||
|
||||
@@ -2360,15 +2360,15 @@ pub(super) mod types {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __reduce__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let args = exc.args();
|
||||
let obj = exc.as_object().to_owned();
|
||||
fn __reduce__(zelf: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
|
||||
let args = zelf.args();
|
||||
let obj = zelf.as_object().to_owned();
|
||||
let mut result: Vec<PyObjectRef> = vec![obj.class().to_owned().into()];
|
||||
|
||||
if args.len() >= 2 && args.len() <= 5 {
|
||||
// SAFETY: len() == 2 is checked so get_arg 1 or 2 won't panic
|
||||
let errno = exc.get_arg(0).unwrap();
|
||||
let msg = exc.get_arg(1).unwrap();
|
||||
let errno = zelf.get_arg(0).unwrap();
|
||||
let msg = zelf.get_arg(1).unwrap();
|
||||
|
||||
if let Ok(filename) = obj.get_attr("filename", vm) {
|
||||
if !vm.is_none(&filename) {
|
||||
|
||||
+29
-29
@@ -450,41 +450,41 @@ mod _io {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __enter__(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
check_closed(&instance, vm)?;
|
||||
Ok(instance)
|
||||
fn __enter__(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
check_closed(&zelf, vm)?;
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn __exit__(instance: PyObjectRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
vm.call_method(&instance, "close", ())?;
|
||||
fn __exit__(zelf: PyObjectRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
vm.call_method(&zelf, "close", ())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn flush(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
fn flush(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
// just check if this is closed; if it isn't, do nothing
|
||||
check_closed(&instance, vm)
|
||||
check_closed(&zelf, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn seekable(_self: PyObjectRef) -> bool {
|
||||
fn seekable(_zelf: PyObjectRef) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn readable(_self: PyObjectRef) -> bool {
|
||||
fn readable(_zelf: PyObjectRef) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn writable(_self: PyObjectRef) -> bool {
|
||||
fn writable(_zelf: PyObjectRef) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn isatty(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
check_closed(&instance, vm)?;
|
||||
fn isatty(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
check_closed(&zelf, vm)?;
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
@@ -494,8 +494,8 @@ mod _io {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn close(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
iobase_close(&instance, vm)
|
||||
fn close(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
iobase_close(&zelf, vm)
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
@@ -560,23 +560,23 @@ mod _io {
|
||||
}
|
||||
|
||||
#[pymethod(name = "_checkClosed")]
|
||||
fn check_closed(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_closed(&instance, vm)
|
||||
fn check_closed(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_closed(&zelf, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "_checkReadable")]
|
||||
fn check_readable(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_readable(&instance, vm)
|
||||
fn check_readable(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_readable(&zelf, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "_checkWritable")]
|
||||
fn check_writable(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_writable(&instance, vm)
|
||||
fn check_writable(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_writable(&zelf, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "_checkSeekable")]
|
||||
fn check_seekable(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_seekable(&instance, vm)
|
||||
fn check_seekable(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
|
||||
check_seekable(&zelf, vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,12 +641,12 @@ mod _io {
|
||||
#[pyclass(flags(BASETYPE, HAS_DICT, HAS_WEAKREF))]
|
||||
impl _RawIOBase {
|
||||
#[pymethod]
|
||||
fn read(instance: PyObjectRef, size: OptionalSize, vm: &VirtualMachine) -> PyResult {
|
||||
fn read(zelf: PyObjectRef, size: OptionalSize, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(size) = size.to_usize() {
|
||||
let b = PyByteArray::from(vm.new_zeroed_bytes(size)?).into_ref(&vm.ctx);
|
||||
let n = <Option<isize>>::try_from_object(
|
||||
vm,
|
||||
vm.call_method(&instance, "readinto", (b.clone(),))?,
|
||||
vm.call_method(&zelf, "readinto", (b.clone(),))?,
|
||||
)?;
|
||||
Ok(match n {
|
||||
None => vm.ctx.none(),
|
||||
@@ -665,18 +665,18 @@ mod _io {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
vm.call_method(&instance, "readall", ())
|
||||
vm.call_method(&zelf, "readall", ())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn readall(instance: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<Vec<u8>>> {
|
||||
fn readall(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<Option<Vec<u8>>> {
|
||||
let mut chunks = Vec::new();
|
||||
let mut total_len = 0;
|
||||
loop {
|
||||
// Loop with EINTR handling (PEP 475)
|
||||
let data = loop {
|
||||
let res = vm.call_method(&instance, "read", (DEFAULT_BUFFER_SIZE,));
|
||||
let res = vm.call_method(&zelf, "read", (DEFAULT_BUFFER_SIZE,));
|
||||
match trap_eintr(res, vm)? {
|
||||
Some(val) => break val,
|
||||
None => continue,
|
||||
@@ -707,12 +707,12 @@ mod _io {
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn readinto(_instance: PyObjectRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
fn readinto(_zelf: PyObjectRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.new_not_implemented_error(String::new()))
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn write(_instance: PyObjectRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
fn write(_zelf: PyObjectRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.new_not_implemented_error(String::new()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
||||
# __text_signature__ is generated from the Rust parameter list, so it must not
|
||||
@@ -47,6 +48,17 @@ assert str(inspect.signature(isinstance)) == "(obj, class_or_tuple, /)"
|
||||
assert str(inspect.signature(issubclass)) == "(cls, class_or_tuple, /)"
|
||||
assert str(inspect.signature(aiter)) == "(async_iterable, /)"
|
||||
|
||||
# A generated signature is stored in __doc__ and read back out of it, so it
|
||||
# needs the `--` terminator even when the function has no documentation.
|
||||
assert str(inspect.signature(os.getpid)) == "()"
|
||||
assert str(inspect.signature(os.getcwd)) == "()"
|
||||
|
||||
# Methods report a signature too, with the receiver marked so that binding a
|
||||
# method drops it.
|
||||
assert str(inspect.signature(list.__dir__)) == "(self, /)"
|
||||
assert str(inspect.signature([].__dir__)) == "()"
|
||||
assert str(inspect.signature(float.fromhex)) == "(string, /)"
|
||||
|
||||
if sys.implementation.name == "rustpython":
|
||||
# Functions whose Rust arguments are destructuring patterns rather than
|
||||
# plain names get no signature at all, instead of emitting text that is not
|
||||
|
||||
Reference in new issue
Block a user