Repository: certbot/certbot

Issue:
`-n` doesn't like `force_interactive`?
Using `-n` to dodge some questions about vhosts:

```
certbot --config-dir /tmp/sample-config --agree-t --regi certonly --apache  --test-cert -n -d b.encryption-example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1): acme-staging.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for b.encryption-example.com
Cleaning up challenges
An unexpected error occurred:
TypeError: menu() got an unexpected keyword argument 'force_interactive'
Please see the logfiles in /var/log/letsencrypt for more details.
```
`-n` doesn't like `force_interactive`?
Using `-n` to dodge some questions about vhosts:

```
certbot --config-dir /tmp/sample-config --agree-t --regi certonly --apache  --test-cert -n -d b.encryption-example.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1): acme-staging.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for b.encryption-example.com
Cleaning up challenges
An unexpected error occurred:
TypeError: menu() got an unexpected keyword argument 'force_interactive'
Please see the logfiles in /var/log/letsencrypt for more details.
```


Discussion:
Ugh. Problem is only one `*` on `unused_kwargs` here: https://github.com/certbot/certbot/blob/master/certbot/display/util.py#L441
Ugh. Problem is only one `*` on `unused_kwargs` here: https://github.com/certbot/certbot/blob/master/certbot/display/util.py#L441

Resolving patch:
diff --git a/certbot/display/util.py b/certbot/display/util.py
--- a/certbot/display/util.py
+++ b/certbot/display/util.py
@@ -438,7 +438,7 @@ def notification(self, message, pause=False, wrap=True, **unused_kwargs):
                 line=os.linesep, frame=side_frame, msg=message))
 
     def menu(self, message, choices, ok_label=None, cancel_label=None,
-             help_label=None, default=None, cli_flag=None, *unused_kwargs):
+             help_label=None, default=None, cli_flag=None, **unused_kwargs):
         # pylint: disable=unused-argument,too-many-arguments
         """Avoid displaying a menu.
 


Test patch:
diff --git a/certbot/tests/display/util_test.py b/certbot/tests/display/util_test.py
--- a/certbot/tests/display/util_test.py
+++ b/certbot/tests/display/util_test.py
@@ -1,10 +1,12 @@
 """Test :mod:`certbot.display.util`."""
+import inspect
 import os
 import unittest
 
 import mock
 
-import certbot.errors as errors
+from certbot import errors
+from certbot import interfaces
 
 from certbot.display import util as display_util
 
@@ -259,6 +261,13 @@ def test_get_valid_int_ans_invalid(self):
                     self.displayer._get_valid_int_ans(3),
                     (display_util.CANCEL, -1))
 
+    def test_methods_take_force_interactive(self):
+        # Every IDisplay method implemented by FileDisplay must take
+        # force_interactive to prevent workflow regressions.
+        for name in interfaces.IDisplay.names():  # pylint: disable=no-member
+            arg_spec = inspect.getargspec(getattr(self.displayer, name))
+            self.assertTrue("force_interactive" in arg_spec.args)
+
 
 class NoninteractiveDisplayTest(unittest.TestCase):
     """Test non-interactive display.
@@ -309,6 +318,16 @@ def test_directory_select(self):
         self.assertRaises(
             errors.MissingCommandlineFlag, self.displayer.directory_select, "msg")
 
+    def test_methods_take_kwargs(self):
+        # Every IDisplay method implemented by NoninteractiveDisplay
+        # should take **kwargs because every method of FileDisplay must
+        # take force_interactive which doesn't apply to
+        # NoninteractiveDisplay.
+        for name in interfaces.IDisplay.names():  # pylint: disable=no-member
+            method = getattr(self.displayer, name)
+            # asserts method accepts arbitrary keyword arguments
+            self.assertFalse(inspect.getargspec(method).keywords is None)
+
 
 class SeparateListInputTest(unittest.TestCase):
     """Test Module functions."""