54
54
ModuleType ,
55
55
)
56
56
from typing import (
57
+ IO ,
57
58
Any ,
58
59
Callable ,
59
60
Dict ,
@@ -601,11 +602,14 @@ def register_command_set(self, cmdset: CommandSet) -> None:
601
602
raise CommandSetRegistrationError (f'Duplicate settable { key } is already registered' )
602
603
603
604
cmdset .on_register (self )
604
- methods = inspect .getmembers (
605
- cmdset ,
606
- predicate = lambda meth : isinstance (meth , Callable ) # type: ignore[arg-type]
607
- and hasattr (meth , '__name__' )
608
- and meth .__name__ .startswith (COMMAND_FUNC_PREFIX ),
605
+ methods = cast (
606
+ List [Tuple [str , Callable [..., Any ]]],
607
+ inspect .getmembers (
608
+ cmdset ,
609
+ predicate = lambda meth : isinstance (meth , Callable ) # type: ignore[arg-type]
610
+ and hasattr (meth , '__name__' )
611
+ and meth .__name__ .startswith (COMMAND_FUNC_PREFIX ),
612
+ ),
609
613
)
610
614
611
615
default_category = getattr (cmdset , CLASS_ATTR_DEFAULT_HELP_CATEGORY , None )
@@ -1056,7 +1060,40 @@ def visible_prompt(self) -> str:
1056
1060
"""
1057
1061
return ansi .strip_style (self .prompt )
1058
1062
1059
- def poutput (self , msg : Any = '' , * , end : str = '\n ' , apply_style : bool = True ) -> None :
1063
+ def print_to (
1064
+ self ,
1065
+ dest : Union [TextIO , IO [str ]],
1066
+ msg : Any ,
1067
+ * ,
1068
+ end : str = '\n ' ,
1069
+ style : Optional [Callable [[str ], str ]] = None ,
1070
+ paged : bool = False ,
1071
+ chop : bool = False ,
1072
+ ) -> None :
1073
+ final_msg = style (msg ) if style is not None else msg
1074
+ if paged :
1075
+ self .ppaged (final_msg , end = end , chop = chop , dest = dest )
1076
+ else :
1077
+ try :
1078
+ ansi .style_aware_write (dest , f'{ final_msg } { end } ' )
1079
+ except BrokenPipeError :
1080
+ # This occurs if a command's output is being piped to another
1081
+ # process and that process closes before the command is
1082
+ # finished. If you would like your application to print a
1083
+ # warning message, then set the broken_pipe_warning attribute
1084
+ # to the message you want printed.
1085
+ if self .broken_pipe_warning :
1086
+ sys .stderr .write (self .broken_pipe_warning )
1087
+
1088
+ def poutput (
1089
+ self ,
1090
+ msg : Any = '' ,
1091
+ * ,
1092
+ end : str = '\n ' ,
1093
+ apply_style : bool = True ,
1094
+ paged : bool = False ,
1095
+ chop : bool = False ,
1096
+ ) -> None :
1060
1097
"""Print message to self.stdout and appends a newline by default
1061
1098
1062
1099
Also handles BrokenPipeError exceptions for when a command's output has
@@ -1067,62 +1104,85 @@ def poutput(self, msg: Any = '', *, end: str = '\n', apply_style: bool = True) -
1067
1104
:param end: string appended after the end of the message, default a newline
1068
1105
:param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
1069
1106
where the message text already has the desired style. Defaults to True.
1107
+ :param paged: If True, pass the output through the configured pager.
1108
+ :param chop: If paged is True, True to truncate long lines or False to wrap long lines.
1070
1109
"""
1071
- if apply_style :
1072
- final_msg = ansi .style_output (msg )
1073
- else :
1074
- final_msg = str (msg )
1075
- try :
1076
- ansi .style_aware_write (self .stdout , f"{ final_msg } { end } " )
1077
- except BrokenPipeError :
1078
- # This occurs if a command's output is being piped to another
1079
- # process and that process closes before the command is
1080
- # finished. If you would like your application to print a
1081
- # warning message, then set the broken_pipe_warning attribute
1082
- # to the message you want printed.
1083
- if self .broken_pipe_warning :
1084
- sys .stderr .write (self .broken_pipe_warning )
1110
+ self .print_to (self .stdout , msg , end = end , style = ansi .style_output if apply_style else None , paged = paged , chop = chop )
1085
1111
1086
- def psuccess (self , msg : Any = '' , * , end : str = '\n ' , apply_style : bool = True ) -> None :
1087
- """Wraps poutput but applies ansi.style_success by default
1112
+ # noinspection PyMethodMayBeStatic
1113
+ def perror (
1114
+ self ,
1115
+ msg : Any = '' ,
1116
+ * ,
1117
+ end : str = '\n ' ,
1118
+ apply_style : bool = True ,
1119
+ paged : bool = False ,
1120
+ chop : bool = False ,
1121
+ ) -> None :
1122
+ """Print message to sys.stderr
1088
1123
1089
1124
:param msg: object to print
1090
1125
:param end: string appended after the end of the message, default a newline
1091
- :param apply_style: If True, then ansi.style_success will be applied to the message text. Set to False in cases
1126
+ :param apply_style: If True, then ansi.style_error will be applied to the message text. Set to False in cases
1092
1127
where the message text already has the desired style. Defaults to True.
1128
+ :param paged: If True, pass the output through the configured pager.
1129
+ :param chop: If paged is True, True to truncate long lines or False to wrap long lines.
1093
1130
"""
1094
- if apply_style :
1095
- msg = ansi .style_success (msg )
1096
- else :
1097
- msg = str (msg )
1098
- self .poutput (msg , end = end , apply_style = False )
1131
+ self .print_to (sys .stderr , msg , end = end , style = ansi .style_error if apply_style else None , paged = paged , chop = chop )
1099
1132
1100
- # noinspection PyMethodMayBeStatic
1101
- def perror (self , msg : Any = '' , * , end : str = '\n ' , apply_style : bool = True ) -> None :
1102
- """Print message to sys.stderr
1133
+ def psuccess (
1134
+ self ,
1135
+ msg : Any = '' ,
1136
+ * ,
1137
+ end : str = '\n ' ,
1138
+ paged : bool = False ,
1139
+ chop : bool = False ,
1140
+ ) -> None :
1141
+ """Writes to stdout applying ansi.style_success by default
1103
1142
1104
1143
:param msg: object to print
1105
1144
:param end: string appended after the end of the message, default a newline
1106
- :param apply_style : If True, then ansi.style_error will be applied to the message text. Set to False in cases
1107
- where the message text already has the desired style. Defaults to True .
1145
+ :param paged : If True, pass the output through the configured pager.
1146
+ :param chop: If paged is True, True to truncate long lines or False to wrap long lines .
1108
1147
"""
1109
- if apply_style :
1110
- final_msg = ansi .style_error (msg )
1111
- else :
1112
- final_msg = str (msg )
1113
- ansi .style_aware_write (sys .stderr , final_msg + end )
1148
+ self .print_to (self .stdout , msg , end = end , style = ansi .style_success , paged = paged , chop = chop )
1114
1149
1115
- def pwarning (self , msg : Any = '' , * , end : str = '\n ' , apply_style : bool = True ) -> None :
1150
+ def pwarning (
1151
+ self ,
1152
+ msg : Any = '' ,
1153
+ * ,
1154
+ end : str = '\n ' ,
1155
+ apply_style : bool = True ,
1156
+ paged : bool = False ,
1157
+ chop : bool = False ,
1158
+ ) -> None :
1116
1159
"""Wraps perror, but applies ansi.style_warning by default
1117
1160
1118
1161
:param msg: object to print
1119
1162
:param end: string appended after the end of the message, default a newline
1120
1163
:param apply_style: If True, then ansi.style_warning will be applied to the message text. Set to False in cases
1121
1164
where the message text already has the desired style. Defaults to True.
1165
+ :param paged: If True, pass the output through the configured pager.
1166
+ :param chop: If paged is True, True to truncate long lines or False to wrap long lines.
1122
1167
"""
1123
- if apply_style :
1124
- msg = ansi .style_warning (msg )
1125
- self .perror (msg , end = end , apply_style = False )
1168
+ self .print_to (sys .stderr , msg , end = end , style = ansi .style_warning if apply_style else None , paged = paged , chop = chop )
1169
+
1170
+ def pfailure (
1171
+ self ,
1172
+ msg : Any = '' ,
1173
+ * ,
1174
+ end : str = '\n ' ,
1175
+ paged : bool = False ,
1176
+ chop : bool = False ,
1177
+ ) -> None :
1178
+ """Writes to stderr applying ansi.style_error by default
1179
+
1180
+ :param msg: object to print
1181
+ :param end: string appended after the end of the message, default a newline
1182
+ :param paged: If True, pass the output through the configured pager.
1183
+ :param chop: If paged is True, True to truncate long lines or False to wrap long lines.
1184
+ """
1185
+ self .print_to (sys .stderr , msg , end = end , style = ansi .style_error , paged = paged , chop = chop )
1126
1186
1127
1187
def pexcept (self , msg : Any , * , end : str = '\n ' , apply_style : bool = True ) -> None :
1128
1188
"""Print Exception message to sys.stderr. If debug is true, print exception traceback if one exists.
@@ -1151,25 +1211,39 @@ def pexcept(self, msg: Any, *, end: str = '\n', apply_style: bool = True) -> Non
1151
1211
1152
1212
self .perror (final_msg , end = end , apply_style = False )
1153
1213
1154
- def pfeedback (self , msg : Any , * , end : str = '\n ' , apply_style : bool = True ) -> None :
1214
+ def pfeedback (
1215
+ self ,
1216
+ msg : Any ,
1217
+ * ,
1218
+ end : str = '\n ' ,
1219
+ apply_style : bool = True ,
1220
+ paged : bool = False ,
1221
+ chop : bool = False ,
1222
+ ) -> None :
1155
1223
"""For printing nonessential feedback. Can be silenced with `quiet`.
1156
1224
Inclusion in redirected output is controlled by `feedback_to_output`.
1157
1225
1158
1226
:param msg: object to print
1159
1227
:param end: string appended after the end of the message, default a newline
1160
1228
:param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
1161
1229
where the message text already has the desired style. Defaults to True.
1230
+ :param paged: If True, pass the output through the configured pager.
1231
+ :param chop: If paged is True, True to truncate long lines or False to wrap long lines.
1162
1232
"""
1163
1233
if not self .quiet :
1164
- if self .feedback_to_output :
1165
- self .poutput (msg , end = end , apply_style = apply_style )
1166
- else :
1167
- self .perror (msg , end = end , apply_style = False )
1234
+ self .print_to (
1235
+ self .stdout if self .feedback_to_output else sys .stderr ,
1236
+ msg ,
1237
+ end = end ,
1238
+ style = ansi .style_output if apply_style else None ,
1239
+ paged = paged ,
1240
+ chop = chop ,
1241
+ )
1168
1242
1169
- def ppaged (self , msg : Any , * , end : str = '\n ' , chop : bool = False , apply_style : bool = True ) -> None :
1243
+ def ppaged (self , msg : Any , * , end : str = '\n ' , chop : bool = False , dest : Optional [ Union [ TextIO , IO [ str ]]] = None ) -> None :
1170
1244
"""Print output using a pager if it would go off screen and stdout isn't currently being redirected.
1171
1245
1172
- Never uses a pager inside of a script (Python or text) or when output is being redirected or piped or when
1246
+ Never uses a pager inside a script (Python or text) or when output is being redirected or piped or when
1173
1247
stdout or stdin are not a fully functional terminal.
1174
1248
1175
1249
:param msg: object to print
@@ -1179,13 +1253,13 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, apply_style:
1179
1253
- chopping is ideal for displaying wide tabular data as is done in utilities like pgcli
1180
1254
False -> causes lines longer than the screen width to wrap to the next line
1181
1255
- wrapping is ideal when you want to keep users from having to use horizontal scrolling
1182
- :param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
1183
- where the message text already has the desired style. Defaults to True.
1256
+ :param dest: Optionally specify the destination stream to write to. If unspecified, defaults to self.stdout
1184
1257
1185
1258
WARNING: On Windows, the text always wraps regardless of what the chop argument is set to
1186
1259
"""
1187
1260
# msg can be any type, so convert to string before checking if it's blank
1188
1261
msg_str = str (msg )
1262
+ dest = self .stdout if dest is None else dest
1189
1263
1190
1264
# Consider None to be no data to print
1191
1265
if msg is None or msg_str == '' :
@@ -1219,7 +1293,7 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, apply_style:
1219
1293
pipe_proc = subprocess .Popen (pager , shell = True , stdin = subprocess .PIPE )
1220
1294
pipe_proc .communicate (msg_str .encode ('utf-8' , 'replace' ))
1221
1295
else :
1222
- self . poutput ( msg_str , end = end , apply_style = apply_style )
1296
+ ansi . style_aware_write ( dest , f' { msg_str } { end } ' )
1223
1297
except BrokenPipeError :
1224
1298
# This occurs if a command's output is being piped to another process and that process closes before the
1225
1299
# command is finished. If you would like your application to print a warning message, then set the
0 commit comments