Add _repr_pretty_ for IPython
This commit is contained in:
parent
cdf39c3464
commit
e5dcb746ad
|
@ -37,6 +37,15 @@ class Namespace(MutableMapping):
|
||||||
raise KeyError(repr(name))
|
raise KeyError(repr(name))
|
||||||
return namespacify(attr)
|
return namespacify(attr)
|
||||||
|
|
||||||
|
def __setitem__(self, name: Any, value: Any) -> None:
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
def __delitem__(self, name: Any) -> None:
|
||||||
|
try:
|
||||||
|
delattr(self, name)
|
||||||
|
except AttributeError:
|
||||||
|
raise KeyError(repr(name))
|
||||||
|
|
||||||
def __iter__(self) -> Iterator:
|
def __iter__(self) -> Iterator:
|
||||||
return iter(self.__dict__)
|
return iter(self.__dict__)
|
||||||
|
|
||||||
|
@ -49,14 +58,14 @@ class Namespace(MutableMapping):
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return str(self.__dict__)
|
return str(self.__dict__)
|
||||||
|
|
||||||
|
def _repr_pretty_(self, p: Any, cycle: bool) -> None:
|
||||||
|
# IPython's pretty printing
|
||||||
|
if cycle:
|
||||||
|
p.text('{}(...)'.format(self.__class__.__name__))
|
||||||
|
else:
|
||||||
|
p.text('{}('.format(self.__class__.__name__))
|
||||||
|
p.pretty(self.__dict__)
|
||||||
|
p.text(')')
|
||||||
|
|
||||||
def copy(self) -> 'Namespace':
|
def copy(self) -> 'Namespace':
|
||||||
return self.__class__(self.__dict__)
|
return self.__class__(self.__dict__)
|
||||||
|
|
||||||
def __setitem__(self, name: Any, value: Any) -> None:
|
|
||||||
setattr(self, name, value)
|
|
||||||
|
|
||||||
def __delitem__(self, name: Any) -> None:
|
|
||||||
try:
|
|
||||||
delattr(self, name)
|
|
||||||
except AttributeError:
|
|
||||||
raise KeyError(repr(name))
|
|
||||||
|
|
|
@ -34,6 +34,15 @@ class ClassRegistry(Dict[str, Callable]):
|
||||||
self.check(key, value)
|
self.check(key, value)
|
||||||
super().__setitem__(key, value)
|
super().__setitem__(key, value)
|
||||||
|
|
||||||
|
def _repr_pretty_(self, p: Any, cycle: bool) -> None:
|
||||||
|
# IPython's pretty printing
|
||||||
|
if cycle:
|
||||||
|
p.text('{}(...)'.format(self.__class__.__name__))
|
||||||
|
else:
|
||||||
|
p.text('{}('.format(self.__class__.__name__))
|
||||||
|
p.pretty(dict(self))
|
||||||
|
p.text(')')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def metaclass(self) -> type:
|
def metaclass(self) -> type:
|
||||||
class RegistryMetaclass(type):
|
class RegistryMetaclass(type):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from types import MappingProxyType
|
from types import MappingProxyType
|
||||||
from typing import List, Set, Iterable, Iterator, Any
|
from typing import List, Set, Iterable, Iterator, Any
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from unittest.mock import MagicMock, call
|
||||||
from objtools.collections import namespacify, Namespace
|
from objtools.collections import namespacify, Namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,29 +70,6 @@ class TestNamespace(TestCase):
|
||||||
with self.assertRaises(AttributeError):
|
with self.assertRaises(AttributeError):
|
||||||
ns.b
|
ns.b
|
||||||
|
|
||||||
def test_iter(self) -> None:
|
|
||||||
ns: Namespace = Namespace(a=1, b=2)
|
|
||||||
iterator: Iterator = iter(ns)
|
|
||||||
self.assertEqual(next(iterator), 'a')
|
|
||||||
self.assertEqual(next(iterator), 'b')
|
|
||||||
|
|
||||||
def test_len(self) -> None:
|
|
||||||
self.assertEqual(len(Namespace(a=1, b=2)), 2)
|
|
||||||
self.assertEqual(len(Namespace()), 0)
|
|
||||||
|
|
||||||
def test_repr(self) -> None:
|
|
||||||
self.assertEqual(repr(Namespace()), 'Namespace({})')
|
|
||||||
self.assertEqual(repr(Namespace(a=1)), "Namespace({'a': 1})")
|
|
||||||
|
|
||||||
def test_str(self) -> None:
|
|
||||||
self.assertEqual(str(Namespace()), '{}')
|
|
||||||
self.assertEqual(str(Namespace(a=1)), "{'a': 1}")
|
|
||||||
|
|
||||||
def test_copy(self) -> None:
|
|
||||||
ns: Namespace = Namespace(a=1, b=2)
|
|
||||||
self.assertEqual(ns.copy(), ns)
|
|
||||||
self.assertIsNot(ns.copy(), ns)
|
|
||||||
|
|
||||||
def test_set(self) -> None:
|
def test_set(self) -> None:
|
||||||
ns: Any = Namespace(a=4)
|
ns: Any = Namespace(a=4)
|
||||||
ns.a = 1
|
ns.a = 1
|
||||||
|
@ -111,3 +89,44 @@ class TestNamespace(TestCase):
|
||||||
del ns.c
|
del ns.c
|
||||||
with self.assertRaises(KeyError):
|
with self.assertRaises(KeyError):
|
||||||
del ns['c']
|
del ns['c']
|
||||||
|
|
||||||
|
def test_iter(self) -> None:
|
||||||
|
ns: Namespace = Namespace(a=1, b=2)
|
||||||
|
iterator: Iterator = iter(ns)
|
||||||
|
self.assertEqual(next(iterator), 'a')
|
||||||
|
self.assertEqual(next(iterator), 'b')
|
||||||
|
|
||||||
|
def test_len(self) -> None:
|
||||||
|
self.assertEqual(len(Namespace(a=1, b=2)), 2)
|
||||||
|
self.assertEqual(len(Namespace()), 0)
|
||||||
|
|
||||||
|
def test_repr(self) -> None:
|
||||||
|
self.assertEqual(repr(Namespace()), 'Namespace({})')
|
||||||
|
self.assertEqual(repr(Namespace(a=1)), "Namespace({'a': 1})")
|
||||||
|
|
||||||
|
def test_str(self) -> None:
|
||||||
|
self.assertEqual(str(Namespace()), '{}')
|
||||||
|
self.assertEqual(str(Namespace(a=1)), "{'a': 1}")
|
||||||
|
|
||||||
|
def test_repr_pretty(self) -> None:
|
||||||
|
p = MagicMock(spec_set=['text', 'pretty'])
|
||||||
|
Namespace(a=1)._repr_pretty_(p, cycle=False)
|
||||||
|
self.assertEqual(p.text.call_count, 2)
|
||||||
|
self.assertEqual(p.pretty.call_count, 1)
|
||||||
|
self.assertListEqual(p.text.call_args_list, [
|
||||||
|
call('Namespace('),
|
||||||
|
call(')'),
|
||||||
|
])
|
||||||
|
self.assertEqual(p.pretty.call_args, call({'a': 1}))
|
||||||
|
|
||||||
|
def test_repr_pretty_cycle(self) -> None:
|
||||||
|
p = MagicMock(spec_set=['text', 'pretty'])
|
||||||
|
Namespace(a=1)._repr_pretty_(p, cycle=True)
|
||||||
|
self.assertEqual(p.text.call_count, 1)
|
||||||
|
self.assertFalse(p.pretty.called)
|
||||||
|
self.assertEqual(p.text.call_args, call('Namespace(...)'))
|
||||||
|
|
||||||
|
def test_copy(self) -> None:
|
||||||
|
ns: Namespace = Namespace(a=1, b=2)
|
||||||
|
self.assertEqual(ns.copy(), ns)
|
||||||
|
self.assertIsNot(ns.copy(), ns)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch, call, MagicMock
|
||||||
from objtools.registry import ClassRegistry
|
from objtools.registry import ClassRegistry
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,3 +61,21 @@ class TestRegistry(TestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.assertDictEqual(registry, {'foo': Thing})
|
self.assertDictEqual(registry, {'foo': Thing})
|
||||||
|
|
||||||
|
def test_repr_pretty(self) -> None:
|
||||||
|
p = MagicMock(spec_set=['text', 'pretty'])
|
||||||
|
ClassRegistry(a=object)._repr_pretty_(p, cycle=False)
|
||||||
|
self.assertEqual(p.text.call_count, 2)
|
||||||
|
self.assertEqual(p.pretty.call_count, 1)
|
||||||
|
self.assertListEqual(p.text.call_args_list, [
|
||||||
|
call('ClassRegistry('),
|
||||||
|
call(')'),
|
||||||
|
])
|
||||||
|
self.assertEqual(p.pretty.call_args, call({'a': object}))
|
||||||
|
|
||||||
|
def test_repr_pretty_cycle(self) -> None:
|
||||||
|
p = MagicMock(spec_set=['text', 'pretty'])
|
||||||
|
ClassRegistry(a=object)._repr_pretty_(p, cycle=True)
|
||||||
|
self.assertEqual(p.text.call_count, 1)
|
||||||
|
self.assertFalse(p.pretty.called)
|
||||||
|
self.assertEqual(p.text.call_args, call('ClassRegistry(...)'))
|
||||||
|
|
Loading…
Reference in New Issue