Use ordinary fileno lookup in select (#9266)

* Use ordinary fileno lookup in select

Assisted-by: Codex:GPT-6

* Share select descriptor conversion

Assisted-by: Codex:GPT-6
This commit is contained in:
1ndahous3 authored and GitHub committed 2026-10-21 11:59:10 +09:00
1 parent 6f2d4a203d
commit 02f4fbbb62
2 files changed
+48 -9

No files matched your search

+16 -9
View File
@@ -3,7 +3,8 @@
pub(crate) use decl::module_def;
use crate::vm::{
PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, builtins::PyListRef,
PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine,
builtins::{PyInt, PyListRef},
};
use rustpython_host_env::select::{self as host_select, FdSet, RawFd, platform::FD_SETSIZE};
use std::io;
@@ -17,14 +18,20 @@ struct Selectable {
impl TryFromObject for Selectable {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let fno = obj.try_to_value(vm).or_else(|_| {
let meth = vm.get_method_or_type_error(
obj.clone(),
vm.ctx.interned_str("fileno").unwrap(),
|| "select arg must be an int or object with a fileno() method".to_owned(),
)?;
meth.call((), vm)?.try_into_value(vm)
})?;
let fileno;
let fd = if let Some(fd) = obj.downcast_ref::<PyInt>() {
fd
} else {
let meth = vm.get_attribute_opt(&obj, "fileno")?.ok_or_else(|| {
vm.new_type_error("select arg must be an int or object with a fileno() method")
})?;
fileno = meth
.call((), vm)?
.downcast::<PyInt>()
.map_err(|_| vm.new_type_error("fileno() returned a non-integer"))?;
&fileno
};
let fno = fd.try_to_primitive(vm)?;
Ok(Self { obj, fno })
}
}
+32
View File
@@ -167,3 +167,35 @@ if hasattr(select, "poll") and hasattr(signal, "setitimer"):
assert handled == [signal.SIGALRM], handled
idle.close()
idle_peer.close()
# fileno is an ordinary attribute, not a special method.
class InstanceFileno:
pass
class DynamicFileno:
def __getattr__(self, name):
if name == "fileno":
return lookup_reader.fileno
raise AttributeError(name)
class IndexOnly:
def __index__(self):
return lookup_reader.fileno()
lookup_reader, lookup_writer = socket.socketpair()
try:
lookup_writer.send(b"x")
instance = InstanceFileno()
instance.fileno = lookup_reader.fileno
for obj in (instance, DynamicFileno()):
assert select.select([obj], [], [], 0) == ([obj], [], [])
assert_raises(TypeError, select.select, [IndexOnly()], [], [], 0)
instance.fileno = IndexOnly
assert_raises(TypeError, select.select, [instance], [], [], 0)
finally:
lookup_reader.close()
lookup_writer.close()