util_mixins.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. # Copyright (c) OpenMMLab. All rights reserved.
  2. """This module defines the :class:`NiceRepr` mixin class, which defines a
  3. ``__repr__`` and ``__str__`` method that only depend on a custom ``__nice__``
  4. method, which you must define. This means you only have to overload one
  5. function instead of two. Furthermore, if the object defines a ``__len__``
  6. method, then the ``__nice__`` method defaults to something sensible, otherwise
  7. it is treated as abstract and raises ``NotImplementedError``.
  8. To use simply have your object inherit from :class:`NiceRepr`
  9. (multi-inheritance should be ok).
  10. This code was copied from the ubelt library: https://github.com/Erotemic/ubelt
  11. Example:
  12. >>> # Objects that define __nice__ have a default __str__ and __repr__
  13. >>> class Student(NiceRepr):
  14. ... def __init__(self, name):
  15. ... self.name = name
  16. ... def __nice__(self):
  17. ... return self.name
  18. >>> s1 = Student('Alice')
  19. >>> s2 = Student('Bob')
  20. >>> print(f's1 = {s1}')
  21. >>> print(f's2 = {s2}')
  22. s1 = <Student(Alice)>
  23. s2 = <Student(Bob)>
  24. Example:
  25. >>> # Objects that define __len__ have a default __nice__
  26. >>> class Group(NiceRepr):
  27. ... def __init__(self, data):
  28. ... self.data = data
  29. ... def __len__(self):
  30. ... return len(self.data)
  31. >>> g = Group([1, 2, 3])
  32. >>> print(f'g = {g}')
  33. g = <Group(3)>
  34. """
  35. import warnings
  36. class NiceRepr:
  37. """Inherit from this class and define ``__nice__`` to "nicely" print your
  38. objects.
  39. Defines ``__str__`` and ``__repr__`` in terms of ``__nice__`` function
  40. Classes that inherit from :class:`NiceRepr` should redefine ``__nice__``.
  41. If the inheriting class has a ``__len__``, method then the default
  42. ``__nice__`` method will return its length.
  43. Example:
  44. >>> class Foo(NiceRepr):
  45. ... def __nice__(self):
  46. ... return 'info'
  47. >>> foo = Foo()
  48. >>> assert str(foo) == '<Foo(info)>'
  49. >>> assert repr(foo).startswith('<Foo(info) at ')
  50. Example:
  51. >>> class Bar(NiceRepr):
  52. ... pass
  53. >>> bar = Bar()
  54. >>> import pytest
  55. >>> with pytest.warns(None) as record:
  56. >>> assert 'object at' in str(bar)
  57. >>> assert 'object at' in repr(bar)
  58. Example:
  59. >>> class Baz(NiceRepr):
  60. ... def __len__(self):
  61. ... return 5
  62. >>> baz = Baz()
  63. >>> assert str(baz) == '<Baz(5)>'
  64. """
  65. def __nice__(self):
  66. """str: a "nice" summary string describing this module"""
  67. if hasattr(self, '__len__'):
  68. # It is a common pattern for objects to use __len__ in __nice__
  69. # As a convenience we define a default __nice__ for these objects
  70. return str(len(self))
  71. else:
  72. # In all other cases force the subclass to overload __nice__
  73. raise NotImplementedError(
  74. f'Define the __nice__ method for {self.__class__!r}')
  75. def __repr__(self):
  76. """str: the string of the module"""
  77. try:
  78. nice = self.__nice__()
  79. classname = self.__class__.__name__
  80. return f'<{classname}({nice}) at {hex(id(self))}>'
  81. except NotImplementedError as ex:
  82. warnings.warn(str(ex), category=RuntimeWarning)
  83. return object.__repr__(self)
  84. def __str__(self):
  85. """str: the string of the module"""
  86. try:
  87. classname = self.__class__.__name__
  88. nice = self.__nice__()
  89. return f'<{classname}({nice})>'
  90. except NotImplementedError as ex:
  91. warnings.warn(str(ex), category=RuntimeWarning)
  92. return object.__repr__(self)