Skip to content

Commit e97ad7d

Browse files
authored
Merge pull request RustPython#3287 from Snowapril/fix-dir-incompatibility
Fix `dir` incompatibility with cpython
2 parents a81f97d + c10e646 commit e97ad7d

File tree

4 files changed

+40
-11
lines changed

4 files changed

+40
-11
lines changed

vm/src/builtins/genericalias.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
use crate::{
2-
builtins::{PyStr, PyTuple, PyTupleRef, PyTypeRef},
2+
builtins::{PyList, PyStr, PyTuple, PyTupleRef, PyTypeRef},
33
common::hash,
4+
function::IntoPyObject,
45
slots::{Hashable, SlotConstructor},
56
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
67
TypeProtocol, VirtualMachine,
78
};
89
use std::fmt;
910

11+
static ATTR_EXCEPTIONS: [&str; 8] = [
12+
"__origin__",
13+
"__args__",
14+
"__parameters__",
15+
"__mro_entries__",
16+
"__reduce_ex__", // needed so we don't look up object.__reduce_ex__
17+
"__reduce__",
18+
"__copy__",
19+
"__deepcopy__",
20+
];
21+
1022
#[pyclass(module = "types", name = "GenericAlias")]
1123
pub struct PyGenericAlias {
1224
origin: PyTypeRef,
@@ -111,6 +123,17 @@ impl PyGenericAlias {
111123
fn origin(&self) -> PyObjectRef {
112124
self.origin.as_object().clone()
113125
}
126+
127+
#[pymethod(magic)]
128+
fn dir(&self, vm: &VirtualMachine) -> PyResult<PyList> {
129+
let dir = vm.dir(Some(self.origin()))?;
130+
for exc in ATTR_EXCEPTIONS.iter() {
131+
if !dir.contains((*exc).into_pyobject(vm), vm)? {
132+
dir.append((*exc).into_pyobject(vm));
133+
}
134+
}
135+
Ok(dir)
136+
}
114137
}
115138

116139
fn is_typevar(obj: PyObjectRef) -> bool {

vm/src/builtins/list.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ impl PyList {
266266
}
267267

268268
#[pymethod(magic)]
269-
fn contains(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
269+
pub fn contains(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
270270
// TODO: to_vec() cause copy which leads to cost O(N). It need to be improved.
271271
let elements = self.borrow_vec().to_vec();
272272
for elem in elements.iter() {

vm/src/stdlib/builtins.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,7 @@ mod builtins {
191191

192192
#[pyfunction]
193193
fn dir(obj: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult<PyList> {
194-
let seq = match obj {
195-
OptionalArg::Present(obj) => vm
196-
.get_special_method(obj, "__dir__")?
197-
.map_err(|_obj| vm.new_type_error("object does not provide __dir__".to_owned()))?
198-
.invoke((), vm)?,
199-
OptionalArg::Missing => vm.call_method(vm.current_locals()?.as_object(), "keys", ())?,
200-
};
201-
let sorted = sorted(seq, Default::default(), vm)?;
202-
Ok(sorted)
194+
vm.dir(obj.into_option())
203195
}
204196

205197
#[pyfunction]

vm/src/vm.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,20 @@ impl VirtualMachine {
11951195
.invoke(args, self)
11961196
}
11971197

1198+
pub fn dir(&self, obj: Option<PyObjectRef>) -> PyResult<PyList> {
1199+
let seq = match obj {
1200+
Some(obj) => self
1201+
.get_special_method(obj, "__dir__")?
1202+
.map_err(|_obj| self.new_type_error("object does not provide __dir__".to_owned()))?
1203+
.invoke((), self)?,
1204+
None => self.call_method(self.current_locals()?.as_object(), "keys", ())?,
1205+
};
1206+
let items = self.extract_elements(&seq)?;
1207+
let lst = PyList::from(items);
1208+
lst.sort(Default::default(), self)?;
1209+
Ok(lst)
1210+
}
1211+
11981212
#[inline]
11991213
pub(crate) fn get_special_method(
12001214
&self,

0 commit comments

Comments
 (0)