mirror of https://github.com/hero-y/BHRL
105 lines
3.6 KiB
Python
105 lines
3.6 KiB
Python
"""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)
|