codekingpro/portable-devtools
115k
1# Urwid split_repr helper functions2# Copyright (C) 2004-2011 Ian Ward3#4# This library is free software; you can redistribute it and/or5# modify it under the terms of the GNU Lesser General Public6# License as published by the Free Software Foundation; either7# version 2.1 of the License, or (at your option) any later version.8#9# This library is distributed in the hope that it will be useful,10# but WITHOUT ANY WARRANTY; without even the implied warranty of11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12# Lesser General Public License for more details.13#14# You should have received a copy of the GNU Lesser General Public15# License along with this library; if not, write to the Free Software16# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA17#18# Urwid web site: https://urwid.org/19 20 21from __future__ import annotations22 23from inspect import getfullargspec24 25 26def split_repr(self):27 """28 Return a helpful description of the object using29 self._repr_words() and self._repr_attrs() to add30 to the description. This function may be used by31 adding code to your class like this:32 33 >>> class Foo(object):34 ... __repr__ = split_repr35 ...36 ... def _repr_words(self):37 ... return ["words", "here"]38 ...39 ... def _repr_attrs(self):40 ... return {"attrs": "appear too"}41 >>> Foo()42 <Foo words here attrs='appear too'>43 >>> class Bar(Foo):44 ... def _repr_words(self):45 ... return Foo._repr_words(self) + ["too"]46 ...47 ... def _repr_attrs(self):48 ... return dict(Foo._repr_attrs(self), barttr=42)49 >>> Bar()50 <Bar words here too attrs='appear too' barttr=42>51 """52 alist = sorted((str(k), normalize_repr(v)) for k, v in self._repr_attrs().items())53 54 words = self._repr_words()55 if not words and not alist:56 # if we're just going to print the classname fall back57 # to the previous __repr__ implementation instead58 return super(self.__class__, self).__repr__()59 if words and alist:60 words.append("")61 return f"<{self.__class__.__name__} {' '.join(words) + ' '.join([f'{k}={v}' for k, v in alist])}>"62 63 64def normalize_repr(v):65 """66 Return dictionary repr sorted by keys, leave others unchanged67 68 >>> normalize_repr({1: 2, 3: 4, 5: 6, 7: 8})69 '{1: 2, 3: 4, 5: 6, 7: 8}'70 >>> normalize_repr("foo")71 "'foo'"72 """73 if isinstance(v, dict):74 items = sorted((repr(k), repr(v)) for k, v in v.items())75 76 return f"{{{', '.join(f'{k}: {v}' for k, v in items)}}}"77 78 return repr(v)79 80 81def remove_defaults(d, fn):82 """83 Remove keys in d that are set to the default values from84 fn. This method is used to unclutter the _repr_attrs()85 return value.86 87 d will be modified by this function.88 89 Returns d.90 91 >>> class Foo(object):92 ... def __init__(self, a=1, b=2):93 ... self.values = a, b94 ...95 ... __repr__ = split_repr96 ...97 ... def _repr_words(self):98 ... return ["object"]99 ...100 ... def _repr_attrs(self):101 ... d = dict(a=self.values[0], b=self.values[1])102 ... return remove_defaults(d, Foo.__init__)103 >>> Foo(42, 100)104 <Foo object a=42 b=100>105 >>> Foo(10, 2)106 <Foo object a=10>107 >>> Foo()108 <Foo object>109 """110 args, varargs, varkw, defaults, _, _, _ = getfullargspec(fn)111 112 # ignore *varargs and **kwargs113 if varkw:114 del args[-1]115 if varargs:116 del args[-1]117 118 # create a dictionary of args with default values119 ddict = dict(zip(args[len(args) - len(defaults) :], defaults))120 121 for k in list(d.keys()):122 if k in ddict and ddict[k] == d[k]:123 # remove values that match their defaults124 del d[k]125 126 return d127 128 129def _test():130 import doctest131 132 doctest.testmod()133 134 135if __name__ == "__main__":136 _test()137 