Skip to content

Commit 3c3801b

Browse files
committed
Improve defaultdict some more
1 parent 501c555 commit 3c3801b

File tree

4 files changed

+37
-7
lines changed

4 files changed

+37
-7
lines changed

Lib/collections/_defaultdict.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
1+
from reprlib import recursive_repr as _recursive_repr
2+
13
class defaultdict(dict):
24
def __init__(self, *args, **kwargs):
35
if len(args) >= 1:
46
default_factory = args[0]
7+
if default_factory is not None and not callable(default_factory):
8+
raise TypeError("first argument must be callable or None")
59
args = args[1:]
610
else:
711
default_factory = None
812
super().__init__(*args, **kwargs)
913
self.default_factory = default_factory
1014

1115
def __missing__(self, key):
12-
if self.default_factory:
16+
if self.default_factory is not None:
1317
val = self.default_factory()
1418
else:
1519
raise KeyError(key)
1620
self[key] = val
1721
return val
1822

23+
@_recursive_repr()
24+
def __repr_factory(factory):
25+
return repr(factory)
26+
1927
def __repr__(self):
20-
return f"defaultdict({self.default_factory}, {dict.__repr__(self)})"
28+
return f"{type(self).__name__}({defaultdict.__repr_factory(self.default_factory)}, {dict.__repr__(self)})"
29+
30+
def copy(self):
31+
return type(self)(self.default_factory, self)
32+
33+
__copy__ = copy
34+
35+
def __reduce__(self):
36+
if self.default_factory is not None:
37+
args = self.default_factory,
38+
else:
39+
args = ()
40+
return type(self), args, None, None, iter(self.items())
2141

42+
defaultdict.__module__ = 'collections'

Lib/test/test_copy.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,6 @@ class C(object):
714714
self.assertEqual(x.foo, y.foo)
715715
self.assertIsNot(x.foo, y.foo)
716716

717-
# TODO: RUSTPYTHON
718-
@unittest.expectedFailure
719717
def test_deepcopy_dict_subclass(self):
720718
class C(dict):
721719
def __init__(self, d=None):

vm/Lib/python_builtins/__reducelib.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def reduce_2(obj):
6363
state = getstate()
6464

6565
listitems = iter(obj) if isinstance(obj, list) else None
66-
dictitems = obj.iteritems() if isinstance(obj, dict) else None
66+
dictitems = iter(obj.items()) if isinstance(obj, dict) else None
6767

6868
newobj = copyreg.__newobj__
6969

vm/src/builtins/function.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,20 @@ impl PyBoundMethod {
449449

450450
#[pymethod(magic)]
451451
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
452+
let funcname = if let Some(qname) =
453+
vm.get_attribute_opt(self.function.clone(), "__qualname__")?
454+
{
455+
Some(qname)
456+
} else if let Some(name) = vm.get_attribute_opt(self.function.clone(), "__qualname__")? {
457+
Some(name)
458+
} else {
459+
None
460+
};
461+
let funcname: Option<PyStrRef> = funcname.and_then(|o| o.downcast().ok());
452462
Ok(format!(
453-
"<bound method of {}>",
454-
vm.to_repr(&self.object)?.borrow_value()
463+
"<bound method {} of {}>",
464+
funcname.as_ref().map_or("?", |s| s.borrow_value()),
465+
vm.to_repr(&self.object)?.borrow_value(),
455466
))
456467
}
457468

0 commit comments

Comments
 (0)