5454 ModuleType ,
5555)
5656from typing import (
57+ IO ,
5758 Any ,
5859 Callable ,
5960 Dict ,
@@ -601,11 +602,14 @@ def register_command_set(self, cmdset: CommandSet) -> None:
601602 raise CommandSetRegistrationError (f'Duplicate settable { key } is already registered' )
602603
603604 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+ ),
609613 )
610614
611615 default_category = getattr (cmdset , CLASS_ATTR_DEFAULT_HELP_CATEGORY , None )
@@ -1056,7 +1060,40 @@ def visible_prompt(self) -> str:
10561060 """
10571061 return ansi .strip_style (self .prompt )
10581062
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 :
10601097 """Print message to self.stdout and appends a newline by default
10611098
10621099 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) -
10671104 :param end: string appended after the end of the message, default a newline
10681105 :param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
10691106 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.
10701109 """
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 )
10851111
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
10881123
10891124 :param msg: object to print
10901125 :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
10921127 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.
10931130 """
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 )
10991132
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
11031142
11041143 :param msg: object to print
11051144 :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 .
11081147 """
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 )
11141149
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 :
11161159 """Wraps perror, but applies ansi.style_warning by default
11171160
11181161 :param msg: object to print
11191162 :param end: string appended after the end of the message, default a newline
11201163 :param apply_style: If True, then ansi.style_warning will be applied to the message text. Set to False in cases
11211164 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.
11221167 """
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 )
11261186
11271187 def pexcept (self , msg : Any , * , end : str = '\n ' , apply_style : bool = True ) -> None :
11281188 """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
11511211
11521212 self .perror (final_msg , end = end , apply_style = False )
11531213
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 :
11551223 """For printing nonessential feedback. Can be silenced with `quiet`.
11561224 Inclusion in redirected output is controlled by `feedback_to_output`.
11571225
11581226 :param msg: object to print
11591227 :param end: string appended after the end of the message, default a newline
11601228 :param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
11611229 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.
11621232 """
11631233 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+ )
11681242
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 :
11701244 """Print output using a pager if it would go off screen and stdout isn't currently being redirected.
11711245
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
11731247 stdout or stdin are not a fully functional terminal.
11741248
11751249 :param msg: object to print
@@ -1179,13 +1253,13 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, apply_style:
11791253 - chopping is ideal for displaying wide tabular data as is done in utilities like pgcli
11801254 False -> causes lines longer than the screen width to wrap to the next line
11811255 - 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
11841257
11851258 WARNING: On Windows, the text always wraps regardless of what the chop argument is set to
11861259 """
11871260 # msg can be any type, so convert to string before checking if it's blank
11881261 msg_str = str (msg )
1262+ dest = self .stdout if dest is None else dest
11891263
11901264 # Consider None to be no data to print
11911265 if msg is None or msg_str == '' :
@@ -1219,7 +1293,7 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, apply_style:
12191293 pipe_proc = subprocess .Popen (pager , shell = True , stdin = subprocess .PIPE )
12201294 pipe_proc .communicate (msg_str .encode ('utf-8' , 'replace' ))
12211295 else :
1222- self . poutput ( msg_str , end = end , apply_style = apply_style )
1296+ ansi . style_aware_write ( dest , f' { msg_str } { end } ' )
12231297 except BrokenPipeError :
12241298 # This occurs if a command's output is being piped to another process and that process closes before the
12251299 # command is finished. If you would like your application to print a warning message, then set the
0 commit comments