123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- # Copyright (c) OpenMMLab. All rights reserved.
- """This module defines the :class:`NiceRepr` mixin class, which defines a
- ``__repr__`` and ``__str__`` method that only depend on a custom ``__nice__``
- method, which you must define. This means you only have to overload one
- function instead of two. Furthermore, if the object defines a ``__len__``
- method, then the ``__nice__`` method defaults to something sensible, otherwise
- it is treated as abstract and raises ``NotImplementedError``.
- To use simply have your object inherit from :class:`NiceRepr`
- (multi-inheritance should be ok).
- This code was copied from the ubelt library: https://github.com/Erotemic/ubelt
- Example:
- >>> # Objects that define __nice__ have a default __str__ and __repr__
- >>> class Student(NiceRepr):
- ... def __init__(self, name):
- ... self.name = name
- ... def __nice__(self):
- ... return self.name
- >>> s1 = Student('Alice')
- >>> s2 = Student('Bob')
- >>> print(f's1 = {s1}')
- >>> print(f's2 = {s2}')
- s1 = <Student(Alice)>
- s2 = <Student(Bob)>
- Example:
- >>> # Objects that define __len__ have a default __nice__
- >>> class Group(NiceRepr):
- ... def __init__(self, data):
- ... self.data = data
- ... def __len__(self):
- ... return len(self.data)
- >>> g = Group([1, 2, 3])
- >>> print(f'g = {g}')
- g = <Group(3)>
- """
- import warnings
- class NiceRepr:
- """Inherit from this class and define ``__nice__`` to "nicely" print your
- objects.
- Defines ``__str__`` and ``__repr__`` in terms of ``__nice__`` function
- Classes that inherit from :class:`NiceRepr` should redefine ``__nice__``.
- If the inheriting class has a ``__len__``, method then the default
- ``__nice__`` method will return its length.
- Example:
- >>> class Foo(NiceRepr):
- ... def __nice__(self):
- ... return 'info'
- >>> foo = Foo()
- >>> assert str(foo) == '<Foo(info)>'
- >>> assert repr(foo).startswith('<Foo(info) at ')
- Example:
- >>> class Bar(NiceRepr):
- ... pass
- >>> bar = Bar()
- >>> import pytest
- >>> with pytest.warns(None) as record:
- >>> assert 'object at' in str(bar)
- >>> assert 'object at' in repr(bar)
- Example:
- >>> class Baz(NiceRepr):
- ... def __len__(self):
- ... return 5
- >>> baz = Baz()
- >>> assert str(baz) == '<Baz(5)>'
- """
- def __nice__(self):
- """str: a "nice" summary string describing this module"""
- if hasattr(self, '__len__'):
- # It is a common pattern for objects to use __len__ in __nice__
- # As a convenience we define a default __nice__ for these objects
- return str(len(self))
- else:
- # In all other cases force the subclass to overload __nice__
- raise NotImplementedError(
- f'Define the __nice__ method for {self.__class__!r}')
- def __repr__(self):
- """str: the string of the module"""
- try:
- nice = self.__nice__()
- classname = self.__class__.__name__
- return f'<{classname}({nice}) at {hex(id(self))}>'
- except NotImplementedError as ex:
- warnings.warn(str(ex), category=RuntimeWarning)
- return object.__repr__(self)
- def __str__(self):
- """str: the string of the module"""
- try:
- classname = self.__class__.__name__
- nice = self.__nice__()
- return f'<{classname}({nice})>'
- except NotImplementedError as ex:
- warnings.warn(str(ex), category=RuntimeWarning)
- return object.__repr__(self)
|