diff --git a/tests/snippets/builtin_dir.py b/tests/snippets/builtin_dir.py index b5fbf8d0b..3e808597c 100644 --- a/tests/snippets/builtin_dir.py +++ b/tests/snippets/builtin_dir.py @@ -1,3 +1,5 @@ +assert isinstance(dir(), list) +assert '__builtins__' in dir() class A: def test(): @@ -21,6 +23,16 @@ assert ['h', 'q'] == dir(B()) # This calls type.__dir__ so isn't changed (but inheritance works)! assert 'test' in dir(A) +# eval() takes any mapping-like type, so dir() must support them +# TODO: eval() should take any mapping as locals, not just dict-derived types +class A(dict): + def __getitem__(self, x): + return dir + def keys(self): + yield 6 + yield 5 +assert eval("dir()", {}, A()) == [5, 6] + import socket assert "AF_INET" in dir(socket) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 3250bef80..7206fe579 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -111,15 +111,13 @@ fn builtin_delattr(obj: PyObjectRef, attr: PyStringRef, vm: &VirtualMachine) -> vm.del_attr(&obj, attr.into_object()) } -fn builtin_dir(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - if args.args.is_empty() { - Ok(vm.get_locals().into_object()) - } else { - let obj = args.args.into_iter().next().unwrap(); - let seq = vm.call_method(&obj, "__dir__", vec![])?; - let sorted = builtin_sorted(vm, PyFuncArgs::new(vec![seq], vec![]))?; - Ok(sorted) - } +fn builtin_dir(obj: OptionalArg, vm: &VirtualMachine) -> PyResult { + let seq = match obj { + OptionalArg::Present(obj) => vm.call_method(&obj, "__dir__", vec![])?, + OptionalArg::Missing => vm.call_method(&vm.get_locals().into_object(), "keys", vec![])?, + }; + let sorted = builtin_sorted(vm, PyFuncArgs::new(vec![seq], vec![]))?; + Ok(sorted) } fn builtin_divmod(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { @@ -136,6 +134,7 @@ fn builtin_divmod(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { /// Implements `eval`. /// See also: https://docs.python.org/3/library/functions.html#eval fn builtin_eval(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { + // TODO: support any mapping for `locals` arg_check!( vm, args,