GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add _types module by youknowone · Pull Request #6807 · RustPython/RustPython

Add _types module #6807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Sign up for GitHub

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
youknowone merged 5 commits into RustPython:main from youknowone:_types
Feb 8, 2026

Uh oh!

There was an error while loading. Please reload this page.

Merged

Add _types module #6807

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
5 commits
Select commit Hold shift + click to select a range
997f948
_types
youknowone Jan 19, 2026
2a30d04
builtin_function_or_method
youknowone Jan 24, 2026
343e07c
PyCapsule
youknowone Jan 24, 2026
592821c
function_or_method
youknowone Feb 8, 2026
68563ad
Remove expectedFailure for test_builtin_function and test_join_nondae…
youknowone Feb 8, 2026
File filter
Filter by extension

Clear filters
Conversations
Failed to load comments.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Jump to
Jump to file
Failed to load files.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Diff view
Diff view

There are no files selected for viewing

1 change: 0 additions & 1 deletion 1 Lib/test/test_reprlib.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ def test_lambda(self):
self.assertStartsWith(r, "<function ReprTests.test_lambda.<locals>.<lambda")
# XXX anonymous functions? see func_repr

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_builtin_function(self):
eq = self.assertEqual
# Functions
Expand Down
1 change: 0 additions & 1 deletion 1 Lib/test/test_threading.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,6 @@ def func(frame, event, arg):
sys.settrace(func)
""")

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_join_nondaemon_on_shutdown(self):
# Issue 1722344
# Raising SystemExit skipped threading._shutdown
Expand Down
196 changes: 90 additions & 106 deletions 196 crates/vm/src/builtins/builtin_func.rs
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{
use alloc::fmt;

// PyCFunctionObject in CPython
#[repr(C)]
#[pyclass(name = "builtin_function_or_method", module = false)]
pub struct PyNativeFunction {
pub(crate) value: &'static PyMethodDef,
Expand Down Expand Up @@ -68,13 +69,65 @@ impl Callable for PyNativeFunction {
#[inline]
fn call(zelf: &Py<Self>, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
if let Some(z) = &zelf.zelf {
args.prepend_arg(z.clone());
// STATIC methods store the class in zelf for qualname/repr purposes,
// but should not prepend it to args (the Rust function doesn't expect it).
if !zelf.value.flags.contains(PyMethodFlags::STATIC) {
args.prepend_arg(z.clone());
}
}
(zelf.value.func)(vm, args)
}
}

#[pyclass(with(Callable), flags(HAS_DICT, DISALLOW_INSTANTIATION))]
// meth_richcompare in CPython
impl Comparable for PyNativeFunction {
fn cmp(
zelf: &Py<Self>,
other: &PyObject,
op: PyComparisonOp,
_vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
op.eq_only(|| {
if let Some(other) = other.downcast_ref::<Self>() {
let eq = match (zelf.zelf.as_ref(), other.zelf.as_ref()) {
(Some(z), Some(o)) => z.is(o),
(None, None) => true,
_ => false,
};
let eq = eq && core::ptr::eq(zelf.value, other.value);
Ok(eq.into())
} else {
Ok(PyComparisonValue::NotImplemented)
}
})
}
}

// meth_repr in CPython
impl Representable for PyNativeFunction {
#[inline]
fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
if let Some(bound) = zelf
.zelf
.as_ref()
.filter(|b| !b.class().is(vm.ctx.types.module_type))
{
Ok(format!(
"<built-in method {} of {} object at {:#x}>",
zelf.value.name,
bound.class().name(),
bound.get_id()
))
} else {
Ok(format!("<built-in function {}>", zelf.value.name))
}
}
}

#[pyclass(
with(Callable, Comparable, Representable),
flags(HAS_DICT, DISALLOW_INSTANTIATION)
)]
impl PyNativeFunction {
#[pygetset]
fn __module__(zelf: NativeFunctionOrMethod) -> Option<&'static PyStrInterned> {
Expand All @@ -86,20 +139,19 @@ impl PyNativeFunction {
zelf.0.value.name
}

// meth_get__qualname__ in CPython
#[pygetset]
fn __qualname__(zelf: NativeFunctionOrMethod, vm: &VirtualMachine) -> PyResult<PyStrRef> {
let zelf = zelf.0;
let flags = zelf.value.flags;
// if flags.contains(PyMethodFlags::CLASS) || flags.contains(PyMethodFlags::STATIC) {
let qualname = if let Some(bound) = &zelf.zelf {
let prefix = if flags.contains(PyMethodFlags::CLASS) {
bound
.get_attr("__qualname__", vm)
.unwrap()
.str(vm)
.unwrap()
.to_string()
if bound.class().is(vm.ctx.types.module_type) {
return Ok(vm.ctx.intern_str(zelf.value.name).to_owned());
}
let prefix = if bound.class().is(vm.ctx.types.type_type) {
// m_self is a type: use PyType_GetQualName(m_self)
bound.get_attr("__qualname__", vm)?.str(vm)?.to_string()
} else {
// m_self is an instance: use Py_TYPE(m_self).__qualname__
bound.class().name().to_string()
};
vm.ctx.new_str(format!("{}.{}", prefix, &zelf.value.name))
Expand All @@ -114,15 +166,23 @@ impl PyNativeFunction {
zelf.0.value.doc
}

// meth_get__self__ in CPython
#[pygetset]
fn __self__(_zelf: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.none()
fn __self__(zelf: NativeFunctionOrMethod, vm: &VirtualMachine) -> PyObjectRef {
zelf.0.zelf.clone().unwrap_or_else(|| vm.ctx.none())
}

// meth_reduce in CPython
#[pymethod]
const fn __reduce__(&self) -> &'static str {
// TODO: return (getattr, (self.object, self.name)) if this is a method
self.value.name
fn __reduce__(zelf: NativeFunctionOrMethod, vm: &VirtualMachine) -> PyResult {
let zelf = zelf.0;
if zelf.zelf.is_none() || zelf.module.is_some() {
Ok(vm.ctx.new_str(zelf.value.name).into())
} else {
let getattr = vm.builtins.get_attr("getattr", vm)?;
let target = zelf.zelf.clone().unwrap();
Ok(vm.new_tuple((getattr, (target, zelf.value.name))).into())
}
}

#[pymethod]
Expand All @@ -138,54 +198,20 @@ impl PyNativeFunction {
}
}

impl Representable for PyNativeFunction {
#[inline]
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
Ok(format!("<built-in function {}>", zelf.value.name))
}
}

// `PyCMethodObject` in CPython
#[pyclass(name = "builtin_method", module = false, base = PyNativeFunction, ctx = "builtin_method_type")]
// PyCMethodObject in CPython
// repr(C) ensures `func` is at offset 0, allowing safe cast from PyNativeMethod to PyNativeFunction
#[repr(C)]
#[pyclass(name = "builtin_function_or_method", module = false, base = PyNativeFunction, ctx = "builtin_function_or_method_type")]
pub struct PyNativeMethod {
pub(crate) func: PyNativeFunction,
pub(crate) class: &'static Py<PyType>, // TODO: the actual life is &'self
}

#[pyclass(
with(Callable, Comparable, Representable),
flags(HAS_DICT, DISALLOW_INSTANTIATION)
)]
impl PyNativeMethod {
#[pygetset]
fn __qualname__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyStrRef> {
let prefix = zelf.class.name().to_string();
Ok(vm
.ctx
.new_str(format!("{}.{}", prefix, &zelf.func.value.name)))
}

#[pymethod]
fn __reduce__(
&self,
vm: &VirtualMachine,
) -> PyResult<(PyObjectRef, (PyObjectRef, &'static str))> {
// TODO: return (getattr, (self.object, self.name)) if this is a method
let getattr = vm.builtins.get_attr("getattr", vm)?;
let target = self
.func
.zelf
.clone()
.unwrap_or_else(|| self.class.to_owned().into());
let name = self.func.value.name;
Ok((getattr, (target, name)))
}

#[pygetset]
fn __self__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> Option<PyObjectRef> {
zelf.func.zelf.clone()
}
}
// All Python-visible behavior (getters, slots) is registered by PyNativeFunction::extend_class.
// PyNativeMethod only extends the Rust-side struct with the defining class reference.
// The func field at offset 0 (#[repr(C)]) allows NativeFunctionOrMethod to read it safely.
#[pyclass(flags(HAS_DICT, DISALLOW_INSTANTIATION))]
impl PyNativeMethod {}

impl fmt::Debug for PyNativeMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -198,63 +224,21 @@ impl fmt::Debug for PyNativeMethod {
}
}

impl Comparable for PyNativeMethod {
fn cmp(
zelf: &Py<Self>,
other: &PyObject,
op: PyComparisonOp,
_vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
op.eq_only(|| {
if let Some(other) = other.downcast_ref::<Self>() {
let eq = match (zelf.func.zelf.as_ref(), other.func.zelf.as_ref()) {
(Some(z), Some(o)) => z.is(o),
(None, None) => true,
_ => false,
};
let eq = eq && core::ptr::eq(zelf.func.value, other.func.value);
Ok(eq.into())
} else {
Ok(PyComparisonValue::NotImplemented)
}
})
}
}

impl Callable for PyNativeMethod {
type Args = FuncArgs;

#[inline]
fn call(zelf: &Py<Self>, mut args: FuncArgs, vm: &VirtualMachine) -> PyResult {
if let Some(zelf) = &zelf.func.zelf {
args.prepend_arg(zelf.clone());
}
(zelf.func.value.func)(vm, args)
}
}

impl Representable for PyNativeMethod {
#[inline]
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
Ok(format!(
"<built-in method {} of {} object at ...>",
&zelf.func.value.name,
zelf.class.name()
))
}
}

pub fn init(context: &Context) {
PyNativeFunction::extend_class(context, context.types.builtin_function_or_method_type);
PyNativeMethod::extend_class(context, context.types.builtin_method_type);
}

/// Wrapper that provides access to the common PyNativeFunction data
/// for both PyNativeFunction and PyNativeMethod (which has func as its first field).
struct NativeFunctionOrMethod(PyRef<PyNativeFunction>);

impl TryFromObject for NativeFunctionOrMethod {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let class = vm.ctx.types.builtin_function_or_method_type;
if obj.fast_isinstance(class) {
// Both PyNativeFunction and PyNativeMethod share the same type now.
// PyNativeMethod has `func: PyNativeFunction` as its first field,
// so we can safely treat the data pointer as PyNativeFunction for reading.
Ok(Self(unsafe { obj.downcast_unchecked() }))
} else {
Err(vm.new_downcast_type_error(class, &obj))
Expand Down
33 changes: 33 additions & 0 deletions 33 crates/vm/src/builtins/capsule.rs
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use super::PyType;
use crate::{Context, Py, PyPayload, PyResult, class::PyClassImpl, types::Representable};

/// PyCapsule - a container for C pointers.
/// In RustPython, this is a minimal implementation for compatibility.
#[pyclass(module = false, name = "PyCapsule")]
#[derive(Debug, Clone, Copy)]
pub struct PyCapsule {
// Capsules store opaque pointers; we don't expose the actual pointer functionality
// since RustPython doesn't have the same C extension model as CPython.
_private: (),
}

impl PyPayload for PyCapsule {
#[inline]
fn class(ctx: &Context) -> &'static Py<PyType> {
ctx.types.capsule_type
}
}

#[pyclass(with(Representable), flags(DISALLOW_INSTANTIATION))]
impl PyCapsule {}

impl Representable for PyCapsule {
#[inline]
fn repr_str(_zelf: &Py<Self>, _vm: &crate::VirtualMachine) -> PyResult<String> {
Ok("<capsule object>".to_string())
}
}

pub fn init(context: &Context) {
PyCapsule::extend_class(context, context.types.capsule_type);
}
2 changes: 2 additions & 0 deletions 2 crates/vm/src/builtins/mod.rs
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub(crate) mod bytearray;
pub use bytearray::PyByteArray;
pub(crate) mod bytes;
pub use bytes::{PyBytes, PyBytesRef};
pub(crate) mod capsule;
pub use capsule::PyCapsule;
pub(crate) mod classmethod;
pub use classmethod::PyClassMethod;
pub(crate) mod code;
Expand Down
10 changes: 8 additions & 2 deletions 10 crates/vm/src/function/method.rs
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ impl PyMethodDef {
) -> PyRef<PyNativeMethod> {
PyRef::new_ref(
self.to_bound_method(obj, class),
ctx.types.builtin_method_type.to_owned(),
ctx.types.builtin_function_or_method_type.to_owned(),
None,
)
}
Expand All @@ -211,7 +211,13 @@ impl PyMethodDef {
class: &'static Py<PyType>,
) -> PyRef<PyNativeMethod> {
debug_assert!(self.flags.contains(PyMethodFlags::STATIC));
let func = self.to_function();
// Set zelf to the class, matching CPython's m_self = type for static methods.
// Callable::call skips prepending when STATIC flag is set.
let func = PyNativeFunction {
zelf: Some(class.to_owned().into()),
value: self,
module: None,
};
PyNativeMethod { func, class }.into_ref(ctx)
}

Expand Down
Loading
Oops, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Loading
Oops, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.