@@ -54,14 +54,93 @@ def _simple(item): # type: (typing.Any) -> bool
54
54
return not isinstance (item , (list , set , tuple , dict , frozenset ))
55
55
56
56
57
+ class ReprParameter (object ):
58
+ """Parameter wrapper wor repr and str operations over signature."""
59
+
60
+ __slots__ = (
61
+ '_value' ,
62
+ '_parameter'
63
+ )
64
+
65
+ POSITIONAL_ONLY = Parameter .POSITIONAL_ONLY
66
+ POSITIONAL_OR_KEYWORD = Parameter .POSITIONAL_OR_KEYWORD
67
+ VAR_POSITIONAL = Parameter .VAR_POSITIONAL
68
+ KEYWORD_ONLY = Parameter .KEYWORD_ONLY
69
+ VAR_KEYWORD = Parameter .VAR_KEYWORD
70
+
71
+ empty = Parameter .empty
72
+
73
+ def __init__ (
74
+ self ,
75
+ parameter , # type: Parameter
76
+ value = None # type: typing.Optional[typing.Any]
77
+ ): # type: (...) -> None
78
+ """Parameter-like object store for repr and str tasks.
79
+
80
+ :param parameter: parameter from signature
81
+ :type parameter: inspect.Parameter
82
+ :param value: default value override
83
+ :type value: typing.Any
84
+ """
85
+ self ._parameter = parameter
86
+ self ._value = value if value is not None else parameter .default
87
+
88
+ @property
89
+ def parameter (self ): # type: () -> Parameter
90
+ """Parameter object."""
91
+ return self ._parameter
92
+
93
+ @property
94
+ def name (self ): # type: () -> typing.Union[None, str]
95
+ """Parameter name.
96
+
97
+ For `*args` and `**kwargs` add prefixes
98
+ """
99
+ if self .kind == Parameter .VAR_POSITIONAL :
100
+ return '*' + self .parameter .name
101
+ elif self .kind == Parameter .VAR_KEYWORD :
102
+ return '**' + self .parameter .name
103
+ return self .parameter .name
104
+
105
+ @property
106
+ def value (self ): # type: () -> typing.Any
107
+ """Parameter value to log.
108
+
109
+ If function is bound to class -> value is class instance else default value.
110
+ """
111
+ return self ._value
112
+
113
+ @property
114
+ def annotation (self ): # type: () -> typing.Union[Parameter.empty, str]
115
+ """Parameter annotation."""
116
+ return self .parameter .annotation
117
+
118
+ @property
119
+ def kind (self ): # type: () -> int
120
+ """Parameter kind."""
121
+ return self .parameter .kind
122
+
123
+ def __hash__ (self ): # pragma: no cover
124
+ """Block hashing.
125
+
126
+ :raises TypeError: Not hashable.
127
+ """
128
+ msg = "unhashable type: '{0}'" .format (self .__class__ .__name__ )
129
+ raise TypeError (msg )
130
+
131
+ def __repr__ (self ):
132
+ """Debug purposes."""
133
+ return '<{} "{}">' .format (self .__class__ .__name__ , self )
134
+
135
+
57
136
# pylint: disable=no-member
58
137
def _prepare_repr (
59
138
func # type: typing.Union[types.FunctionType, types.MethodType]
60
- ): # type: (...) -> typing.Iterator[typing.Union[str, typing.Tuple[str, typing.Any]] ]
139
+ ): # type: (...) -> typing.Iterator[ReprParameter ]
61
140
"""Get arguments lists with defaults.
62
141
63
142
:type func: typing.Union[types.FunctionType, types.MethodType]
64
- :rtype: typing.Iterator[typing.Union[str, typing.Tuple[str, typing.Any]] ]
143
+ :rtype: typing.Iterator[ReprParameter ]
65
144
"""
66
145
isfunction = isinstance (func , types .FunctionType )
67
146
real_func = func if isfunction else func .__func__ # type: typing.Callable
@@ -71,18 +150,11 @@ def _prepare_repr(
71
150
params = iter (parameters )
72
151
if not isfunction and func .__self__ is not None :
73
152
try :
74
- yield next (params ). name , func .__self__
153
+ yield ReprParameter ( next (params ), value = func .__self__ )
75
154
except StopIteration : # pragma: no cover
76
155
return
77
156
for arg in params :
78
- if arg .default != Parameter .empty :
79
- yield arg .name , arg .default
80
- elif arg .kind == Parameter .VAR_POSITIONAL :
81
- yield '*' + arg .name
82
- elif arg .kind == Parameter .VAR_KEYWORD :
83
- yield '**' + arg .name
84
- else :
85
- yield arg .name
157
+ yield ReprParameter (arg )
86
158
# pylint: enable=no-member
87
159
88
160
@@ -455,31 +527,35 @@ def _repr_callable(
455
527
param_str = ""
456
528
457
529
for param in _prepare_repr (src ):
458
- if isinstance (param , tuple ):
459
- param_str += "\n {spc:<{indent}}{key}={val}," .format (
460
- spc = '' ,
461
- indent = self .next_indent (indent ),
462
- key = param [0 ],
530
+ param_str += "\n {spc:<{indent}}{param.name}" .format (
531
+ spc = '' ,
532
+ indent = self .next_indent (indent ),
533
+ param = param
534
+ )
535
+ if param .annotation != param .empty :
536
+ param_str += ': {param.annotation}' .format (param = param )
537
+ if param .value != param .empty :
538
+ param_str += '={val}' .format (
463
539
val = self .process_element (
464
- src = param [ 1 ] ,
540
+ src = param . value ,
465
541
indent = indent ,
466
542
no_indent_start = True ,
467
543
)
468
544
)
469
- else :
470
- param_str += "\n {spc:<{indent}}{key}," .format (
471
- spc = '' ,
472
- indent = self .next_indent (indent ),
473
- key = param
474
- )
545
+ param_str += ','
475
546
476
547
if param_str :
477
548
param_str += "\n " + " " * indent
478
- return "\n {spc:<{indent}}<{obj!r} with interface ({args})>" .format (
549
+
550
+ sig = signature (src )
551
+ annotation = '' if sig .return_annotation == Parameter .empty else ' -> {sig.return_annotation!r}' .format (sig = sig )
552
+
553
+ return "\n {spc:<{indent}}<{obj!r} with interface ({args}){annotation}>" .format (
479
554
spc = "" ,
480
555
indent = indent ,
481
556
obj = src ,
482
557
args = param_str ,
558
+ annotation = annotation
483
559
)
484
560
485
561
@staticmethod
@@ -627,31 +703,35 @@ def _repr_callable(
627
703
param_str = ""
628
704
629
705
for param in _prepare_repr (src ):
630
- if isinstance (param , tuple ):
631
- param_str += "\n {spc:<{indent}}{key}={val}," .format (
632
- spc = '' ,
633
- indent = self .next_indent (indent ),
634
- key = param [0 ],
706
+ param_str += "\n {spc:<{indent}}{param.name}" .format (
707
+ spc = '' ,
708
+ indent = self .next_indent (indent ),
709
+ param = param
710
+ )
711
+ if param .annotation != param .empty :
712
+ param_str += ': {param.annotation}' .format (param = param )
713
+ if param .value != param .empty :
714
+ param_str += '={val}' .format (
635
715
val = self .process_element (
636
- src = param [ 1 ] ,
716
+ src = param . value ,
637
717
indent = indent ,
638
718
no_indent_start = True ,
639
719
)
640
720
)
641
- else :
642
- param_str += "\n {spc:<{indent}}{key}," .format (
643
- spc = '' ,
644
- indent = self .next_indent (indent ),
645
- key = param
646
- )
721
+ param_str += ','
647
722
648
723
if param_str :
649
724
param_str += "\n " + " " * indent
650
- return "\n {spc:<{indent}}<{obj!s} with interface ({args})>" .format (
725
+
726
+ sig = signature (src )
727
+ annotation = '' if sig .return_annotation == Parameter .empty else ' -> {sig.return_annotation!r}' .format (sig = sig )
728
+
729
+ return "\n {spc:<{indent}}<{obj!s} with interface ({args}){annotation}>" .format (
651
730
spc = "" ,
652
731
indent = indent ,
653
732
obj = src ,
654
733
args = param_str ,
734
+ annotation = annotation
655
735
)
656
736
657
737
@staticmethod
0 commit comments