Repository: python-cmd2/cmd2

Issue:
pwarning() should have an apply_style argument
`perror()` and `pexcept()` both have an `apply_style` argument which defaults to `True`. If that argument is `True`, then the method applies an ansi style to the message before sending it to the output stream. `pwarning()`` always applies the style. It should have an `apply_style` argument like it's sister methods.

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index abf29028..780c9ad5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
     * Added capability to override the argument parser class used by cmd2 built-in commands. See override_parser.py
     example for more details.
     * Added `end` argument to `pfeedback()` to be consistent with the other print functions like `poutput()`.
+    * Added `apply_style` to `pwarning()`.
 * Breaking changes
     * For consistency between all the print functions:
         * Made `end` and `chop` keyword-only arguments of `ppaged()`
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 85841b30..1eeb4212 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -467,13 +467,17 @@ class Cmd(cmd.Cmd):
             final_msg = "{}".format(msg)
         ansi.ansi_aware_write(sys.stderr, final_msg + end)
 
-    def pwarning(self, msg: Any, *, end: str = '\n') -> None:
-        """Apply the warning style to a message and print it to sys.stderr
+    def pwarning(self, msg: Any, *, end: str = '\n', apply_style: bool = True) -> None:
+        """Like perror, but applies ansi.style_warning by default
 
         :param msg: message to print (anything convertible to a str with '{}'.format() is OK)
         :param end: string appended after the end of the message, default a newline
+        :param apply_style: If True, then ansi.style_warning will be applied to the message text. Set to False in cases
+                            where the message text already has the desired style. Defaults to True.
         """
-        self.perror(ansi.style_warning(msg), end=end, apply_style=False)
+        if apply_style:
+            msg = ansi.style_warning(msg)
+        self.perror(msg, end=end, apply_style=False)
 
     def pexcept(self, msg: Any, *, end: str = '\n', apply_style: bool = True) -> None:
         """Print Exception message to sys.stderr. If debug is true, print exception traceback if one exists.
@@ -499,7 +503,6 @@ class Cmd(cmd.Cmd):
             warning = "\nTo enable full traceback, run the following command: 'set debug true'"
             final_msg += ansi.style_warning(warning)
 
-        # Set apply_style to False since style has already been applied
         self.perror(final_msg, end=end, apply_style=False)
 
     def pfeedback(self, msg: Any, *, end: str = '\n') -> None:


Test patch:
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index f9c3e61d..88447416 100755
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -1882,6 +1882,38 @@ def test_nonexistent_macro(base_app):
 
     assert exception is not None
 
+def test_perror_style(base_app, capsys):
+    msg = 'testing...'
+    end = '\n'
+    ansi.allow_ansi = ansi.ANSI_ALWAYS
+    base_app.perror(msg)
+    out, err = capsys.readouterr()
+    assert err == ansi.style_error(msg) + end
+
+def test_perror_no_style(base_app, capsys):
+    msg = 'testing...'
+    end = '\n'
+    ansi.allow_ansi = ansi.ANSI_ALWAYS
+    base_app.perror(msg, apply_style=False)
+    out, err = capsys.readouterr()
+    assert err == msg + end
+
+def test_pwarning_style(base_app, capsys):
+    msg = 'testing...'
+    end = '\n'
+    ansi.allow_ansi = ansi.ANSI_ALWAYS
+    base_app.pwarning(msg)
+    out, err = capsys.readouterr()
+    assert err == ansi.style_warning(msg) + end
+
+def test_pwarning_no_style(base_app, capsys):
+    msg = 'testing...'
+    end = '\n'
+    ansi.allow_ansi = ansi.ANSI_ALWAYS
+    base_app.pwarning(msg, apply_style=False)
+    out, err = capsys.readouterr()
+    assert err == msg + end
+
 def test_ppaged(outsim_app):
     msg = 'testing...'
     end = '\n'
@@ -1889,6 +1921,18 @@ def test_ppaged(outsim_app):
     out = outsim_app.stdout.getvalue()
     assert out == msg + end
 
+def test_ppaged_blank(outsim_app):
+    msg = ''
+    outsim_app.ppaged(msg)
+    out = outsim_app.stdout.getvalue()
+    assert not out
+
+def test_ppaged_none(outsim_app):
+    msg = None
+    outsim_app.ppaged(msg)
+    out = outsim_app.stdout.getvalue()
+    assert not out
+
 def test_ppaged_strips_ansi_when_redirecting(outsim_app):
     msg = 'testing...'
     end = '\n'