From 3c3801bbe49036c99b230b2c8de07a03eaa4f5b2 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Wed, 7 Apr 2021 20:03:10 -0500 Subject: [PATCH] Improve defaultdict some more --- Lib/collections/_defaultdict.py | 27 ++++++++++++++++++++++++--- Lib/test/test_copy.py | 2 -- vm/Lib/python_builtins/__reducelib.py | 2 +- vm/src/builtins/function.rs | 15 +++++++++++++-- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/Lib/collections/_defaultdict.py b/Lib/collections/_defaultdict.py index f9a79639f..007ca9104 100644 --- a/Lib/collections/_defaultdict.py +++ b/Lib/collections/_defaultdict.py @@ -1,7 +1,11 @@ +from reprlib import recursive_repr as _recursive_repr + class defaultdict(dict): def __init__(self, *args, **kwargs): if len(args) >= 1: default_factory = args[0] + if default_factory is not None and not callable(default_factory): + raise TypeError("first argument must be callable or None") args = args[1:] else: default_factory = None @@ -9,13 +13,30 @@ class defaultdict(dict): self.default_factory = default_factory def __missing__(self, key): - if self.default_factory: + if self.default_factory is not None: val = self.default_factory() else: raise KeyError(key) self[key] = val return val - def __repr__(self): - return f"defaultdict({self.default_factory}, {dict.__repr__(self)})" + @_recursive_repr() + def __repr_factory(factory): + return repr(factory) + def __repr__(self): + return f"{type(self).__name__}({defaultdict.__repr_factory(self.default_factory)}, {dict.__repr__(self)})" + + def copy(self): + return type(self)(self.default_factory, self) + + __copy__ = copy + + def __reduce__(self): + if self.default_factory is not None: + args = self.default_factory, + else: + args = () + return type(self), args, None, None, iter(self.items()) + +defaultdict.__module__ = 'collections' diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py index ae018a394..abc82aea3 100644 --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -714,8 +714,6 @@ class TestCopy(unittest.TestCase): self.assertEqual(x.foo, y.foo) self.assertIsNot(x.foo, y.foo) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_deepcopy_dict_subclass(self): class C(dict): def __init__(self, d=None): diff --git a/vm/Lib/python_builtins/__reducelib.py b/vm/Lib/python_builtins/__reducelib.py index 78098617f..0067cd0a8 100644 --- a/vm/Lib/python_builtins/__reducelib.py +++ b/vm/Lib/python_builtins/__reducelib.py @@ -63,7 +63,7 @@ def reduce_2(obj): state = getstate() listitems = iter(obj) if isinstance(obj, list) else None - dictitems = obj.iteritems() if isinstance(obj, dict) else None + dictitems = iter(obj.items()) if isinstance(obj, dict) else None newobj = copyreg.__newobj__ diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index 79d4cd6da..f71a36543 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -449,9 +449,20 @@ impl PyBoundMethod { #[pymethod(magic)] fn repr(&self, vm: &VirtualMachine) -> PyResult { + let funcname = if let Some(qname) = + vm.get_attribute_opt(self.function.clone(), "__qualname__")? + { + Some(qname) + } else if let Some(name) = vm.get_attribute_opt(self.function.clone(), "__qualname__")? { + Some(name) + } else { + None + }; + let funcname: Option = funcname.and_then(|o| o.downcast().ok()); Ok(format!( - "", - vm.to_repr(&self.object)?.borrow_value() + "", + funcname.as_ref().map_or("?", |s| s.borrow_value()), + vm.to_repr(&self.object)?.borrow_value(), )) }