Set builtin __doc__, __module__, and datetime signatures (#8897)

* Set builtin __doc__, __module__, and datetime signatures

Expose empty doc-db member entries as ''. Heap __dict__ and __weakref__
getsets carry their descriptor docs. Member repr uses the qualified
type name.

__module__ is collections for the deque iterators, _csv for Dialect,
ctypes for ArgumentError and CField, _lzma for LZMAError, operator for
the getter types, pickle for PickleBuffer, _ssl for MemoryBIO,
SSLSession, _SSLContext and _SSLSocket, weakref for the proxy types,
and posix (nt on Windows) for times_result and uname_result.
unicodedata's copied UCD functions set __module__ to unicodedata.

_testinternalcapi function docs and weakproxy.__str__ use the stored
text. datetime replace defaults render as unchanged, __replace__ is
($self, /, **changes) and binds through replace, now defaults tz to
None, and fromisoformat and tzinfo methods name the parameter object.

Assisted-by: Grok:grok-4.7

* Move doctext helpers above the test module

db_slice and docs sat after mod tests.
Remove expectedFailure from test_html_doc, test_text_doc,
test_help_output_redirect, test_method_aliases, and test_long_signatures.

Assisted-by: Grok:grok-4.7
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-09-29 21:11:06 +09:00
1 parent a242ed1457
commit d54a4c5932
22 files changed
+190 -95

No files matched your search

-5
View File
@@ -419,7 +419,6 @@ class PydocDocTest(unittest.TestCase):
def tearDown(self):
self.assertIs(sys.modules['pydoc'], pydoc)
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __locals__ unexpectedly')
@requires_docstrings
@@ -438,7 +437,6 @@ class PydocDocTest(unittest.TestCase):
self.assertIn(mod_file, result)
self.assertIn(doc_loc, result)
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __locals__ unexpectedly')
@requires_docstrings
@@ -708,7 +706,6 @@ class PydocDocTest(unittest.TestCase):
expected = missing_pattern % "abd"
self.assertEqual(expected, buf.getvalue().strip().replace('\n', os.linesep))
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __locals__ unexpectedly')
@unittest.mock.patch('pydoc.pager')
@@ -1073,7 +1070,6 @@ class PydocDocTest(unittest.TestCase):
methods = pydoc.allmethods(TestClass)
self.assertDictEqual(methods, expected)
@unittest.expectedFailure # TODO: RUSTPYTHON
@requires_docstrings
def test_method_aliases(self):
class A:
@@ -1164,7 +1160,6 @@ class B(A)
for expected_line in expected_lines:
self.assertIn(expected_line, as_text)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_long_signatures(self):
from collections.abc import Callable
from typing import Literal, Annotated
+14 -7
View File
@@ -450,13 +450,20 @@ fn attr_doc_expr(self_ty: Option<&syn::Type>, attr: &str, rust_doc: Option<Strin
<#ty as ::rustpython_vm::class::PyClassDef>::ATTR_DOCS,
#attr,
);
match FOUND {
Some((offset, len)) if len != 0 => ::rustpython_vm::function::ItemDoc {
text: None,
offset,
len,
},
_ => ::rustpython_vm::function::ItemDoc::NONE,
if let Some((offset, len)) = FOUND {
if len != 0 {
::rustpython_vm::function::ItemDoc {
text: None,
offset,
len,
}
} else if offset == u32::MAX {
::rustpython_vm::function::ItemDoc::EMPTY
} else {
::rustpython_vm::function::ItemDoc::NONE
}
} else {
::rustpython_vm::function::ItemDoc::NONE
}
}
} else {
+70 -34
View File
@@ -18,7 +18,7 @@ mod _datetime {
hash::PyHash,
wtf8::{CodePoint, Wtf8Buf},
},
function::{FuncArgs, OptionalArg, PyComparisonValue},
function::{ArgumentError, FromArgs, FuncArgs, OptionalArg, Param, PyComparisonValue},
protocol::{PyNumber, PyNumberMethods},
types::{AsNumber, Comparable, Constructor, Hashable, PyComparisonOp, Representable},
};
@@ -1948,7 +1948,8 @@ mod _datetime {
}
#[pyclassmethod]
fn fromisoformat(cls: PyTypeRef, dtstr: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn fromisoformat(cls: PyTypeRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let dtstr = object;
let Some(s) = dtstr.downcast_ref::<PyStr>() else {
return Err(vm.new_type_error("fromisoformat: argument must be str"));
};
@@ -2069,7 +2070,6 @@ mod _datetime {
}
#[pymethod]
#[pymethod(name = "__replace__")]
fn replace(zelf: &Py<Self>, args: DateReplaceArgs, vm: &VirtualMachine) -> PyResult {
new_date_subclass(
args.year.unwrap_or_else(|| zelf.y()),
@@ -2080,6 +2080,11 @@ mod _datetime {
)
}
#[pymethod]
fn __replace__(zelf: &Py<Self>, changes: ReplaceChanges, vm: &VirtualMachine) -> PyResult {
Self::replace(zelf, changes.args.bind_for(vm, "replace")?, vm)
}
#[pymethod]
fn __reduce__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyRef<PyTuple> {
let state = vm.ctx.new_bytes(zelf.state_bytes().to_vec());
@@ -2121,13 +2126,29 @@ mod _datetime {
day: PyObjectRef,
}
/// `**changes` in the text signature. Binding still accepts the same
/// arguments as `replace`, and a failure names `replace`.
struct ReplaceChanges {
args: FuncArgs,
}
impl FromArgs for ReplaceChanges {
const PARAMS: Option<&'static [Param]> = Some(&[Param::var_keyword("changes")]);
fn from_args(_vm: &VirtualMachine, args: &mut FuncArgs) -> Result<Self, ArgumentError> {
Ok(Self {
args: core::mem::take(args),
})
}
}
#[derive(FromArgs)]
struct DateReplaceArgs {
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
year: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
month: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
day: OptionalArg<i32>,
}
@@ -2327,22 +2348,23 @@ mod _datetime {
#[pyclass(with(Constructor), flags(BASETYPE))]
impl PyTzInfo {
#[pymethod]
fn tzname(&self, _dt: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn tzname(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
tzinfo_nogo("tzname", vm)
}
#[pymethod]
fn utcoffset(&self, _dt: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn utcoffset(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
tzinfo_nogo("utcoffset", vm)
}
#[pymethod]
fn dst(&self, _dt: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn dst(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
tzinfo_nogo("dst", vm)
}
#[pymethod]
fn fromutc(zelf: PyObjectRef, dt: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn fromutc(zelf: PyObjectRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let dt = object;
let Some(dtobj) = as_datetime(&dt) else {
return Err(vm.new_type_error("fromutc: argument must be a datetime"));
};
@@ -2530,25 +2552,29 @@ mod _datetime {
#[pyclass(with(Constructor, Comparable, Hashable, Representable))]
impl PyTimeZone {
#[pymethod]
fn tzname(zelf: &Py<Self>, dt: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
fn tzname(zelf: &Py<Self>, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
let dt = object;
timezone_check_argument(&dt, "tzname", vm)?;
Ok(Self::name_str(zelf, vm))
}
#[pymethod]
fn utcoffset(&self, dt: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<PyDelta>> {
fn utcoffset(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<PyDelta>> {
let dt = object;
timezone_check_argument(&dt, "utcoffset", vm)?;
Ok(self.offset.clone())
}
#[pymethod]
fn dst(&self, dt: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn dst(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let dt = object;
timezone_check_argument(&dt, "dst", vm)?;
Ok(())
}
#[pymethod]
fn fromutc(zelf: &Py<Self>, dt: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn fromutc(zelf: &Py<Self>, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let dt = object;
let Some(dtobj) = as_datetime(&dt) else {
return Err(vm.new_type_error("fromutc: argument must be a datetime"));
};
@@ -2800,17 +2826,17 @@ mod _datetime {
#[derive(FromArgs)]
struct TimeReplaceArgs {
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
hour: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
minute: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
second: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
microsecond: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
tzinfo: OptionalArg<PyObjectRef>,
#[pyarg(named, optional)]
#[pyarg(named, optional, py_default = "unchanged")]
fold: OptionalArg<i32>,
}
@@ -2940,7 +2966,6 @@ mod _datetime {
}
#[pymethod]
#[pymethod(name = "__replace__")]
fn replace(zelf: &Py<Self>, args: TimeReplaceArgs, vm: &VirtualMachine) -> PyResult {
let tzinfo = match args.tzinfo {
OptionalArg::Present(tz) => tzinfo_arg(tz, vm),
@@ -2958,8 +2983,14 @@ mod _datetime {
)
}
#[pymethod]
fn __replace__(zelf: &Py<Self>, changes: ReplaceChanges, vm: &VirtualMachine) -> PyResult {
Self::replace(zelf, changes.args.bind_for(vm, "replace")?, vm)
}
#[pyclassmethod]
fn fromisoformat(cls: PyTypeRef, tstr: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn fromisoformat(cls: PyTypeRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let tstr = object;
let Some(s) = tstr.downcast_ref::<PyStr>() else {
return Err(vm.new_type_error("fromisoformat: argument must be str"));
};
@@ -3576,7 +3607,7 @@ mod _datetime {
#[derive(FromArgs)]
struct NowArgs {
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "None")]
tz: OptionalArg<PyObjectRef>,
}
@@ -3608,23 +3639,23 @@ mod _datetime {
#[derive(FromArgs)]
struct DateTimeReplaceArgs {
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
year: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
month: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
day: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
hour: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
minute: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
second: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
microsecond: OptionalArg<i32>,
#[pyarg(any, optional)]
#[pyarg(any, optional, py_default = "unchanged")]
tzinfo: OptionalArg<PyObjectRef>,
#[pyarg(named, optional)]
#[pyarg(named, optional, py_default = "unchanged")]
fold: OptionalArg<i32>,
}
@@ -3788,7 +3819,8 @@ mod _datetime {
}
#[pyclassmethod]
fn fromisoformat(cls: PyTypeRef, dtstr: PyObjectRef, vm: &VirtualMachine) -> PyResult {
fn fromisoformat(cls: PyTypeRef, object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let dtstr = object;
let Some(s) = dtstr.downcast_ref::<PyStr>() else {
return Err(vm.new_type_error("fromisoformat: argument must be str"));
};
@@ -4053,7 +4085,6 @@ mod _datetime {
}
#[pymethod]
#[pymethod(name = "__replace__")]
fn replace(zelf: &Py<Self>, args: DateTimeReplaceArgs, vm: &VirtualMachine) -> PyResult {
let tzinfo = match args.tzinfo {
OptionalArg::Present(tz) => tzinfo_arg(tz, vm),
@@ -4075,6 +4106,11 @@ mod _datetime {
)
}
#[pymethod]
fn __replace__(zelf: &Py<Self>, changes: ReplaceChanges, vm: &VirtualMachine) -> PyResult {
Self::replace(zelf, changes.args.bind_for(vm, "replace")?, vm)
}
#[pymethod]
fn astimezone(zelf: &Py<Self>, args: AstimezoneArgs, vm: &VirtualMachine) -> PyResult {
let tz = args.tz.unwrap_or_none(vm);
+1 -1
View File
@@ -74,7 +74,7 @@ mod _csv {
}
#[pyattr]
#[pyclass(module = "csv", name = "Dialect")]
#[pyclass(module = "_csv", name = "Dialect")]
#[derive(Debug, PyPayload, Clone)]
struct PyDialect {
delimiter: u8,
+1 -1
View File
@@ -79,7 +79,7 @@ mod _lzma {
#[pyattr(once, name = "LZMAError")]
fn error(vm: &VirtualMachine) -> PyTypeRef {
vm.ctx.new_exception_type_with_doc(
"lzma",
"_lzma",
"LZMAError",
Some(vec![vm.ctx.exceptions.exception_type.to_owned()]),
const { ItemDoc::db("_lzma.LZMAError") },
+4 -4
View File
@@ -841,7 +841,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(module = "ssl", name = "_SSLContext")]
#[pyclass(module = "_ssl", name = "_SSLContext")]
#[derive(PyPayload)]
struct PySslContext {
ctx: PyRwLock<SslContextBuilder>,
@@ -2482,7 +2482,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(module = "ssl", name = "_SSLSocket", traverse)]
#[pyclass(module = "_ssl", name = "_SSLSocket", traverse)]
#[derive(PyPayload)]
struct PySslSocket {
ctx: PyRwLock<PyRef<PySslContext>>,
@@ -3298,7 +3298,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(module = "ssl", name = "SSLSession", unhashable = true)]
#[pyclass(module = "_ssl", name = "SSLSession", unhashable = true)]
#[derive(PyPayload)]
struct PySslSession {
session: *mut sys::SSL_SESSION,
@@ -3358,7 +3358,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(module = "ssl", name = "MemoryBIO")]
#[pyclass(module = "_ssl", name = "MemoryBIO")]
#[derive(PyPayload)]
struct PySslMemoryBio {
bio: *mut sys::BIO,
+1 -1
View File
@@ -68,7 +68,7 @@ mod _pickle {
// PickleBuffer
#[pyattr]
#[pyclass(module = "_pickle", name = "PickleBuffer")]
#[pyclass(module = "pickle", name = "PickleBuffer")]
#[derive(Debug, PyPayload)]
pub(super) struct PyPickleBuffer {
buffer: PyRwLock<Option<PyBuffer>>,
+4 -4
View File
@@ -319,7 +319,7 @@ mod _ssl {
// SSLContext - manages TLS configuration
#[pyattr]
#[pyclass(name = "_SSLContext", module = "ssl", traverse)]
#[pyclass(name = "_SSLContext", module = "_ssl", traverse)]
#[derive(Debug, PyPayload)]
struct PySSLContext {
#[pytraverse(skip)]
@@ -2058,7 +2058,7 @@ mod _ssl {
// SSLSocket - represents a TLS-wrapped socket
#[pyattr]
#[pyclass(name = "_SSLSocket", module = "ssl", traverse)]
#[pyclass(name = "_SSLSocket", module = "_ssl", traverse)]
#[derive(Debug, PyPayload)]
pub(crate) struct PySSLSocket {
io: SocketOrBio,
@@ -3898,7 +3898,7 @@ mod _ssl {
// MemoryBIO - provides in-memory buffer for SSL/TLS I/O
#[pyattr]
#[pyclass(name = "MemoryBIO", module = "ssl")]
#[pyclass(name = "MemoryBIO", module = "_ssl")]
#[derive(Debug, PyPayload)]
struct PyMemoryBIO {
inner: PyMutex<rustpython_host_env::ssl::MemoryBio>,
@@ -3979,7 +3979,7 @@ mod _ssl {
// SSLSession - represents a cached SSL session
// NOTE: This is an EMULATION - actual session data is managed by Rustls internally
#[pyattr]
#[pyclass(name = "SSLSession", module = "ssl", unhashable = true)]
#[pyclass(name = "SSLSession", module = "_ssl", unhashable = true)]
#[derive(Debug, PyPayload)]
struct PySSLSession {
context_identity: Arc<()>,
+3 -3
View File
@@ -179,7 +179,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(name = "_SSLContext", module = "ssl", traverse)]
#[pyclass(name = "_SSLContext", module = "_ssl", traverse)]
#[derive(Debug, PyPayload)]
struct PySSLContext {
#[pytraverse(skip)]
@@ -665,7 +665,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(name = "MemoryBIO", module = "ssl")]
#[pyclass(name = "MemoryBIO", module = "_ssl")]
#[derive(Debug, PyPayload)]
struct PyMemoryBIO {
inner: PyMutex<rustpython_host_env::ssl::MemoryBio>,
@@ -737,7 +737,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(name = "SSLSession", module = "ssl", unhashable = true)]
#[pyclass(name = "SSLSession", module = "_ssl", unhashable = true)]
#[derive(Debug, PyPayload)]
struct PySSLSession {
session_id: Vec<u8>,
+3 -1
View File
@@ -61,7 +61,9 @@ mod unicodedata {
"normalize",
"numeric",
] {
module.set_attr(attr, ucd.get_attr(attr, vm)?, vm)?;
let func = ucd.get_attr(attr, vm)?;
func.set_attr("__module__", vm.ctx.new_str("unicodedata"), vm)?;
module.set_attr(attr, func, vm)?;
}
Ok(())
+1 -1
View File
@@ -1507,7 +1507,7 @@ impl Representable for PyMemberDescriptor {
Ok(format!(
"<member '{}' of '{}' objects>",
zelf.common.name,
zelf.common.typ.name(),
zelf.common.typ.slot_name(),
))
}
}
+12 -9
View File
@@ -2822,9 +2822,11 @@ impl Constructor for PyType {
.iter()
.any(|base| base.attributes.contains(__dict__));
if !typ.attributes.contains(__dict__) && !has_inherited_dict {
let descriptor =
vm.ctx
.new_getset("__dict__", &typ, subtype_get_dict, subtype_set_dict);
let getset = super::PyGetSet::new("__dict__", &typ, &vm.ctx)
.with_get(subtype_get_dict)
.with_set(subtype_set_dict)
.with_doc(ItemDoc::static_text("dictionary for instance variables"));
let descriptor = PyRef::new_ref(getset, vm.ctx.types.getset_type.to_owned(), None);
typ.attributes.set(__dict__, descriptor.into());
}
}
@@ -2838,12 +2840,13 @@ impl Constructor for PyType {
.iter()
.any(|base| base.attributes.contains(__weakref__));
if !typ.attributes.contains(__weakref__) && !has_inherited_weakref {
let descriptor = vm.ctx.new_getset(
"__weakref__",
&typ,
subtype_get_weakref,
subtype_set_weakref,
);
let getset = super::PyGetSet::new("__weakref__", &typ, &vm.ctx)
.with_get(subtype_get_weakref)
.with_set(subtype_set_weakref)
.with_doc(ItemDoc::static_text(
"list of weak references to the object",
));
let descriptor = PyRef::new_ref(getset, vm.ctx.types.getset_type.to_owned(), None);
typ.attributes.set(__weakref__, descriptor.into());
}
}
+3 -2
View File
@@ -13,7 +13,7 @@ use crate::{
},
};
#[pyclass(module = false, name = "weakproxy", unhashable = true)]
#[pyclass(module = "weakref", name = "weakproxy", unhashable = true)]
#[derive(Debug)]
#[repr(transparent)]
pub struct PyWeakProxy(PyWeak);
@@ -78,7 +78,7 @@ impl PyWeakProxy {
}
#[pyclass(
module = false,
module = "weakref",
name = "weakcallableproxy",
base = PyWeakProxy,
ctx = "weakcallableproxy_type",
@@ -123,6 +123,7 @@ impl PyWeakProxy {
self.0.upgrade().ok_or_else(|| new_reference_error(vm))
}
/// Return str(self).
#[pymethod]
fn __str__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
zelf.try_upgrade(vm)?.str(vm)
+11 -8
View File
@@ -231,14 +231,17 @@ pub const fn attr_name_present(table: &[&str], name: &str) -> bool {
#[must_use]
pub fn class_attr_item_doc<T: PyClassDef + ?Sized>(name: &str) -> ItemDoc {
#[cfg(feature = "doc")]
if let Some((offset, len)) = attr_doc(T::ATTR_DOCS, name)
&& len != 0
{
return ItemDoc {
text: None,
offset,
len,
};
if let Some((offset, len)) = attr_doc(T::ATTR_DOCS, name) {
if len != 0 {
return ItemDoc {
text: None,
offset,
len,
};
}
if offset == u32::MAX {
return ItemDoc::EMPTY;
}
}
#[cfg(not(feature = "doc"))]
let _ = name;
+24
View File
@@ -23,6 +23,14 @@ impl ItemDoc {
len: 0,
};
/// An explicit empty docstring. `offset == u32::MAX` distinguishes it from
/// [`NONE`](Self::NONE), which means the item has no docstring at all.
pub const EMPTY: Self = Self {
text: None,
offset: u32::MAX,
len: 0,
};
#[must_use]
pub const fn static_text(text: &'static str) -> Self {
Self {
@@ -73,6 +81,9 @@ pub fn db_doc(offset: u32, len: u32) -> Option<&'static str> {
#[inline(never)]
#[must_use]
pub fn plain_doc(doc: ItemDoc) -> Option<&'static str> {
if doc.offset == u32::MAX && doc.len == 0 {
return Some("");
}
if doc.len != 0 {
return db_doc(doc.offset, doc.len);
}
@@ -109,3 +120,16 @@ fn docs() -> &'static str {
})
.as_ref()
}
#[cfg(test)]
mod tests {
use super::{ItemDoc, plain_doc};
#[test]
fn explicit_empty_doc_is_empty_string() {
assert_eq!(plain_doc(ItemDoc::EMPTY), Some(""));
assert_eq!(plain_doc(ItemDoc::NONE), None);
assert_eq!(plain_doc(ItemDoc::static_text("")), None);
assert_eq!(plain_doc(ItemDoc::static_text("a")), Some("a"));
}
}
+2 -2
View File
@@ -737,7 +737,7 @@ mod _collections {
}
#[pyattr]
#[pyclass(name = "_deque_iterator", traverse)]
#[pyclass(name = "_deque_iterator", module = "collections", traverse)]
#[derive(Debug, PyPayload)]
struct PyDequeIterator {
#[pytraverse(skip)]
@@ -873,7 +873,7 @@ mod _collections {
}
#[pyattr]
#[pyclass(name = "_deque_reverse_iterator", traverse)]
#[pyclass(name = "_deque_reverse_iterator", module = "collections", traverse)]
#[derive(Debug, PyPayload)]
struct PyReverseDequeIterator {
#[pytraverse(skip)]
+1 -1
View File
@@ -257,7 +257,7 @@ pub(crate) mod _ctypes {
#[pyattr(name = "ArgumentError", once)]
fn argument_error(vm: &VirtualMachine) -> PyTypeRef {
vm.ctx.new_exception_type(
"_ctypes",
"ctypes",
"ArgumentError",
Some(vec![vm.ctx.exceptions.exception_type.to_owned()]),
)
+1 -1
View File
@@ -1250,7 +1250,7 @@ impl PyCData {
// PyCField - Field descriptor for Structure/Union types
#[pyclass(name = "CField", module = "_ctypes")]
#[pyclass(name = "CField", module = "ctypes")]
#[derive(Debug, PyPayload)]
pub struct PyCField {
/// Field name
+3 -3
View File
@@ -351,7 +351,7 @@ mod _operator {
}
#[pyattr]
#[pyclass(name = "attrgetter")]
#[pyclass(name = "attrgetter", module = "operator")]
#[derive(Debug, PyPayload)]
struct PyAttrGetter {
attrs: Vec<PyStrRef>,
@@ -468,7 +468,7 @@ mod _operator {
}
#[pyattr]
#[pyclass(name = "itemgetter")]
#[pyclass(name = "itemgetter", module = "operator")]
#[derive(Debug, PyPayload)]
struct PyItemGetter {
items: Vec<PyObjectRef>,
@@ -554,7 +554,7 @@ mod _operator {
}
#[pyattr]
#[pyclass(name = "methodcaller")]
#[pyclass(name = "methodcaller", module = "operator")]
#[derive(Debug, PyPayload)]
struct PyMethodCaller {
name: PyUtf8StrRef,
+13
View File
@@ -291,6 +291,7 @@ mod _testinternalcapi {
}
}
/// C implementation of inspect.cleandoc().
#[pyfunction]
fn compiler_cleandoc(doc: PyStrRef) -> String {
clean_doc(doc.to_str().unwrap_or(""))
@@ -342,6 +343,7 @@ mod _testinternalcapi {
dict_inner::peek_next_keys_version()
}
/// forcefully assign type->tp_version_tag
#[pyfunction]
fn type_assign_specific_version_unsafe(ty: PyTypeRef, version: u32) {
ty.assign_specific_version(version);
@@ -800,12 +802,18 @@ mod _testinternalcapi {
}
}
/// Return a new, empty InstructionSequence.
#[cfg(feature = "codegen")]
#[pyfunction]
fn new_instruction_sequence(vm: &VirtualMachine) -> PyRef<PyInstructionSequence> {
PyInstructionSequence::empty().into_ref(&vm.ctx)
}
/// Apply compiler code generation to an AST.
///
/// Return (instruction_sequence, metadata). metadata maps "argcount",
/// "posonlyargcount", "kwonlyargcount" to ints and "consts" to the list of
/// constants in LOAD_CONST index order (for use with optimize_cfg).
#[cfg(feature = "codegen")]
#[pyfunction]
fn compiler_codegen(
@@ -856,6 +864,10 @@ mod _testinternalcapi {
Ok(vm.ctx.new_tuple(vec![seq.into(), metadata.into()]).into())
}
/// Apply compiler optimizations to an instruction list.
///
/// consts must be a list aligned with LOAD_CONST opargs (the "consts" entry
/// from the metadata dict returned by compiler_codegen for the same unit).
#[cfg(feature = "codegen")]
#[pyfunction]
fn optimize_cfg(
@@ -893,6 +905,7 @@ mod _testinternalcapi {
Ok(PyInstructionSequence::from_rust(optimized, vm))
}
/// Create a code object for the given instructions.
#[cfg(feature = "codegen")]
#[pyfunction]
fn assemble_code_object(
+14 -3
View File
@@ -1944,9 +1944,14 @@ pub(super) mod _os {
pub elapsed: f64,
}
#[cfg(all(any(unix, windows), not(target_os = "redox")))]
#[cfg(all(windows, not(target_os = "redox")))]
#[pyattr]
#[pystruct_sequence(name = "times_result", module = "os", data = "TimesResultData")]
#[pystruct_sequence(name = "times_result", module = "nt", data = "TimesResultData")]
struct PyTimesResult;
#[cfg(all(unix, not(windows), not(target_os = "redox")))]
#[pyattr]
#[pystruct_sequence(name = "times_result", module = "posix", data = "TimesResultData")]
struct PyTimesResult;
#[cfg(all(any(unix, windows), not(target_os = "redox")))]
@@ -2171,8 +2176,14 @@ pub(super) mod _os {
pub machine: String,
}
#[cfg(windows)]
#[pyattr]
#[pystruct_sequence(name = "uname_result", module = "os", data = "UnameResultData")]
#[pystruct_sequence(name = "uname_result", module = "nt", data = "UnameResultData")]
pub(crate) struct PyUnameResult;
#[cfg(not(windows))]
#[pyattr]
#[pystruct_sequence(name = "uname_result", module = "posix", data = "UnameResultData")]
pub(crate) struct PyUnameResult;
#[pyclass(with(PyStructSequence))]
+4 -4
View File
@@ -243,7 +243,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(name = "MemoryBIO", module = "ssl")]
#[pyclass(name = "MemoryBIO", module = "_ssl")]
#[derive(Debug, PyPayload)]
struct PyMemoryBIO {
inner: PyMutex<MemoryBio>,
@@ -299,7 +299,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(name = "SSLSession", module = "ssl")]
#[pyclass(name = "SSLSession", module = "_ssl")]
#[derive(Debug, PyPayload)]
struct PySSLSession {}
@@ -332,7 +332,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(name = "_SSLContext", module = "ssl")]
#[pyclass(name = "_SSLContext", module = "_ssl")]
#[derive(Debug, PyPayload)]
struct PySSLContext {
protocol: i32,
@@ -640,7 +640,7 @@ mod _ssl {
}
#[pyattr]
#[pyclass(name = "_SSLSocket", module = "ssl")]
#[pyclass(name = "_SSLSocket", module = "_ssl")]
#[derive(Debug, PyPayload)]
struct PySSLSocket {
incoming: PyRef<PyMemoryBIO>,