Cleanup some direct magic method definitions (#7441)

* Migrate direct __repr__ definitions to Representable trait

Move legacy #[pymethod] __repr__ to impl Representable for:
- PySSLContext, PySSLSocket (ssl.rs)
- BufferedReader, BufferedWriter, BufferedRandom (_io.rs)

Enable __repr__ guard in derive to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Migrate direct __del__ definition to Destructor trait for PySocket

Move #[pymethod] __del__ to impl Destructor for PySocket.
Preserves ResourceWarning emission and close behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove redundant __iter__ pymethods from PyFuture and PyTask

Both types already have impl Iterable, so the direct #[pymethod]
__iter__ definitions were duplicates. Enable __iter__/__next__
guards in derive to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Enable derive guards for __get__/__set__/__delete__ descriptor methods

All concrete types already use GetDescriptor/SetDescriptor traits.
Activate the compile-time guard to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Enable derive guards for AsMapping/AsSequence slot methods

Remove redundant #[pymethod(name = "__len__")] from PyStr
(already provided via AsMapping/AsSequence trait impls).

Enable compile-time guards for __len__, __contains__, __getitem__,
__setitem__, __delitem__ to prevent future direct definitions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lee DogeonandClaude Opus 4.6 authored and GitHub committed 2026-03-16 22:49:45 +09:00
1 parent 065d355248
commit 2117c92b9b
5 files changed
+67 -71

No files matched your search

+12 -12
View File
@@ -917,7 +917,7 @@ where
("__new__", "Constructor"),
("__init__", "Initializer"),
// Representable trait
// ("__repr__", "Representable"),
("__repr__", "Representable"),
// ("__str__", "???"), // allow __str__
// Hashable trait
("__hash__", "Hashable"),
@@ -927,9 +927,9 @@ where
// NOTE: __getattribute__, __setattr__, __delattr__ are intentionally NOT forbidden
// because they need pymethod for subclass override mechanism to work properly.
// GetDescriptor/SetDescriptor traits
// ("__get__", "GetDescriptor"),
// ("__set__", "SetDescriptor"),
// ("__delete__", "SetDescriptor"),
("__get__", "GetDescriptor"),
("__set__", "SetDescriptor"),
("__delete__", "SetDescriptor"),
// AsNumber trait
("__add__", "AsNumber"),
("__radd__", "AsNumber"),
@@ -981,15 +981,15 @@ where
("__index__", "AsNumber"),
("__bool__", "AsNumber"),
// AsSequence trait
// ("__len__", "AsSequence (or AsMapping)"),
// ("__contains__", "AsSequence"),
("__len__", "AsSequence (or AsMapping)"),
("__contains__", "AsSequence"),
// AsMapping trait
// ("__getitem__", "AsMapping (or AsSequence)"),
// ("__setitem__", "AsMapping (or AsSequence)"),
// ("__delitem__", "AsMapping (or AsSequence)"),
// IterNext trait
// ("__iter__", "IterNext"),
// ("__next__", "IterNext"),
("__getitem__", "AsMapping (or AsSequence)"),
("__setitem__", "AsMapping (or AsSequence)"),
("__delitem__", "AsMapping (or AsSequence)"),
// Iterable/IterNext traits
("__iter__", "Iterable"),
("__next__", "IterNext"),
// Comparable trait
("__eq__", "Comparable"),
("__ne__", "Comparable"),
-12
View File
@@ -764,11 +764,6 @@ pub(crate) mod _asyncio {
Ok(())
}
#[pymethod]
fn __iter__(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyFutureIter> {
Self::__await__(zelf, vm)
}
#[pymethod]
fn __await__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyFutureIter> {
Ok(PyFutureIter {
@@ -1828,13 +1823,6 @@ pub(crate) mod _asyncio {
}
}
#[pymethod]
fn __iter__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyFutureIter> {
Ok(PyFutureIter {
future: PyRwLock::new(Some(zelf.into())),
})
}
#[pymethod]
fn __await__(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyFutureIter> {
Ok(PyFutureIter {
+39 -34
View File
@@ -20,7 +20,7 @@ mod _socket {
ArgBytesLike, ArgIntoFloat, ArgMemoryBuffer, ArgStrOrBytesLike, Either, FsPath,
OptionalArg, OptionalOption,
},
types::{Constructor, DefaultConstructor, Initializer, Representable},
types::{Constructor, DefaultConstructor, Destructor, Initializer, Representable},
utils::ToCString,
};
@@ -1417,7 +1417,44 @@ mod _socket {
}
}
#[pyclass(with(Constructor, Initializer, Representable), flags(BASETYPE))]
impl Destructor for PySocket {
fn del(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<()> {
// Emit ResourceWarning if socket is still open
if zelf.sock.read().is_some() {
let laddr = if let Ok(sock) = zelf.sock()
&& let Ok(addr) = sock.local_addr()
&& let Ok(repr) = get_addr_tuple(&addr, vm).repr(vm)
{
format!(", laddr={}", repr.as_wtf8())
} else {
String::new()
};
let msg = format!(
"unclosed <socket.socket fd={}, family={}, type={}, proto={}{}>",
zelf.fileno(),
zelf.family.load(),
zelf.kind.load(),
zelf.proto.load(),
laddr
);
let _ = crate::vm::warn::warn(
vm.ctx.new_str(msg).into(),
Some(vm.ctx.exceptions.resource_warning.to_owned()),
1,
None,
vm,
);
}
let _ = zelf.close();
Ok(())
}
}
#[pyclass(
with(Constructor, Initializer, Representable, Destructor),
flags(BASETYPE)
)]
impl PySocket {
fn _init(
zelf: PyRef<Self>,
@@ -2139,38 +2176,6 @@ mod _socket {
Ok(())
}
#[pymethod]
fn __del__(&self, vm: &VirtualMachine) {
// Emit ResourceWarning if socket is still open
if self.sock.read().is_some() {
let laddr = if let Ok(sock) = self.sock()
&& let Ok(addr) = sock.local_addr()
&& let Ok(repr) = get_addr_tuple(&addr, vm).repr(vm)
{
format!(", laddr={}", repr.as_wtf8())
} else {
String::new()
};
let msg = format!(
"unclosed <socket.socket fd={}, family={}, type={}, proto={}{}>",
self.fileno(),
self.family.load(),
self.kind.load(),
self.proto.load(),
laddr
);
let _ = crate::vm::warn::warn(
vm.ctx.new_str(msg).into(),
Some(vm.ctx.exceptions.resource_warning.to_owned()),
1,
None,
vm,
);
}
let _ = self.close();
}
#[pymethod]
#[inline]
fn detach(&self) -> i64 {
+16 -12
View File
@@ -857,18 +857,13 @@ mod _ssl {
binary_form: OptionalArg<bool>,
}
#[pyclass(with(Constructor), flags(BASETYPE))]
#[pyclass(with(Constructor, Representable), flags(BASETYPE))]
impl PySSLContext {
// Helper method to convert DER certificate bytes to Python dict
fn cert_der_to_dict(&self, vm: &VirtualMachine, cert_der: &[u8]) -> PyResult<PyObjectRef> {
cert::cert_der_to_dict_helper(vm, cert_der)
}
#[pymethod]
fn __repr__(&self) -> String {
format!("<SSLContext(protocol={})>", self.protocol)
}
#[pygetset]
fn check_hostname(&self) -> bool {
*self.check_hostname.read()
@@ -2191,6 +2186,13 @@ mod _ssl {
}
}
impl Representable for PySSLContext {
#[inline]
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
Ok(format!("<SSLContext(protocol={})>", zelf.protocol))
}
}
impl Constructor for PySSLContext {
type Args = (i32,);
@@ -2374,7 +2376,7 @@ mod _ssl {
Completed, // unwrap() completed successfully
}
#[pyclass(with(Constructor), flags(BASETYPE))]
#[pyclass(with(Constructor, Representable), flags(BASETYPE))]
impl PySSLSocket {
// Check if this is BIO mode
pub(crate) fn is_bio_mode(&self) -> bool {
@@ -3021,11 +3023,6 @@ mod _ssl {
}
}
#[pymethod]
fn __repr__(&self) -> String {
"<SSLSocket>".to_string()
}
// Helper function to convert Python PROTO_* constants to rustls versions
fn get_rustls_versions(
minimum: i32,
@@ -4562,6 +4559,13 @@ mod _ssl {
}
}
impl Representable for PySSLSocket {
#[inline]
fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
Ok("<SSLSocket>".to_owned())
}
}
impl Constructor for PySSLSocket {
type Args = ();
-1
View File
@@ -663,7 +663,6 @@ impl PyStr {
self.data.is_empty()
}
#[pymethod(name = "__len__")]
#[inline]
pub fn char_len(&self) -> usize {
self.data.char_len()