Repository: boto/botocore
Pull request #576 (2015-06-18 02:08:15)

Use **kwargs for method signatures
Ensures if a model driven parameter requires parameters, it is represented as ``**kwargs`` in the method signature. The purpose of doing this is to make the method signatures less cluttered. Note that non-data driven methods still use their method signature.

Here is what it looked before:
![screen shot 2015-06-17 at 7 01 00 pm](https://cloud.githubusercontent.com/assets/4605355/8222746/0ab5b3f8-1524-11e5-9784-dad32250163c.png)

Here is what it looks after:
![screen shot 2015-06-17 at 7 01 08 pm](https://cloud.githubusercontent.com/assets/4605355/8222752/1293fb52-1524-11e5-940d-375ded98f788.png)

cc @jamesls @mtdowling 

jamesls: :shipit:

Patch:
diff --git a/botocore/docs/method.py b/botocore/docs/method.py
index 9ee330d3c..8abb2b3a9 100644
--- a/botocore/docs/method.py
+++ b/botocore/docs/method.py
@@ -55,10 +55,8 @@ def document_model_driven_signature(section, name, operation_model,
         documentation.
     """
     params = {}
-    required = []
     if operation_model.input_shape:
         params = operation_model.input_shape.members
-        required = operation_model.input_shape.required_members
 
     parameter_names = list(params.keys())
 
@@ -71,13 +69,9 @@ def document_model_driven_signature(section, name, operation_model,
             if member in parameter_names:
                 parameter_names.remove(member)
 
-    required_params = [k for k in parameter_names if k in required]
-    optional_params = [k for k in parameter_names if k not in required]
-
-    signature_params = ', '.join([
-        ', '.join(['{0}=None'.format(k) for k in required_params]),
-        ', '.join(['{0}=None'.format(k) for k in optional_params])
-    ]).strip(', ')
+    signature_params = ''
+    if parameter_names:
+        signature_params = '**kwargs'
     section.style.start_sphinx_py_method(name, signature_params)
 
 


Test patch:
diff --git a/tests/unit/docs/test_client.py b/tests/unit/docs/test_client.py
index 5e320e15a..8b0fc23d7 100644
--- a/tests/unit/docs/test_client.py
+++ b/tests/unit/docs/test_client.py
@@ -38,7 +38,7 @@ class TestClientDocumenter(BaseDocsTest):
             '  .. py:method:: can_paginate(operation_name)',
             '  .. py:method:: get_paginator(operation_name)',
             '  .. py:method:: get_waiter(waiter_name)',
-            '  .. py:method:: sample_operation(Biz=None)',
+            '  .. py:method:: sample_operation(**kwargs)',
             '    **Request Syntax**',
             '    ::',
             '      response = client.sample_operation(',
diff --git a/tests/unit/docs/test_method.py b/tests/unit/docs/test_method.py
index ecee0fa27..db9b8df66 100644
--- a/tests/unit/docs/test_method.py
+++ b/tests/unit/docs/test_method.py
@@ -49,26 +49,27 @@ class TestDocumentModelDrivenSignature(BaseDocsTest):
         document_model_driven_signature(
             self.doc_structure, 'my_method', self.operation_model)
         self.assert_contains_line(
-            '.. py:method:: my_method(Bar=None, Foo=None, Baz=None)')
+            '.. py:method:: my_method(**kwargs)')
 
-    def test_document_signature_include(self):
-        include_params = [
-            DocumentedShape(
-                name='Biz', type_name='integer', documentation='biz docs')
-        ]
+    def test_document_signature_exclude_all_kwargs(self):
+        exclude_params = ['Foo', 'Bar', 'Baz']
         document_model_driven_signature(
             self.doc_structure, 'my_method', self.operation_model,
-            include=include_params)
+            exclude=exclude_params)
         self.assert_contains_line(
-            '.. py:method:: my_method(Bar=None, Foo=None, Baz=None, Biz=None)')
+            '.. py:method:: my_method()')
 
-    def test_document_signature_exclude(self):
-        exclude_params = ['Baz']
+    def test_document_signature_exclude_and_include(self):
+        exclude_params = ['Foo', 'Bar', 'Baz']
+        include_params = [
+            DocumentedShape(
+                name='Biz', type_name='integer', documentation='biz docs')
+        ]
         document_model_driven_signature(
             self.doc_structure, 'my_method', self.operation_model,
-            exclude=exclude_params)
+            include=include_params, exclude=exclude_params)
         self.assert_contains_line(
-            '.. py:method:: my_method(Bar=None, Foo=None)')
+            '.. py:method:: my_method(**kwargs)')
 
 
 class TestDocumentCustomSignature(BaseDocsTest):
@@ -116,7 +117,7 @@ class TestDocumentModelDrivenMethod(BaseDocsTest):
             example_prefix='response = client.foo'
         )
         self.assert_contains_lines_in_order([
-            '.. py:method:: foo(Bar=None)',
+            '.. py:method:: foo(**kwargs)',
             '  This describes the foo method.',
             '  **Request Syntax**',
             '  ::',
@@ -168,7 +169,7 @@ class TestDocumentModelDrivenMethod(BaseDocsTest):
             include_input=include_params
         )
         self.assert_contains_lines_in_order([
-            '.. py:method:: foo(Bar=None, Biz=None)',
+            '.. py:method:: foo(**kwargs)',
             '  This describes the foo method.',
             '  **Request Syntax**',
             '  ::',
@@ -205,7 +206,7 @@ class TestDocumentModelDrivenMethod(BaseDocsTest):
             include_output=include_params
         )
         self.assert_contains_lines_in_order([
-            '.. py:method:: foo(Bar=None)',
+            '.. py:method:: foo(**kwargs)',
             '  This describes the foo method.',
             '  **Request Syntax**',
             '  ::',
@@ -238,7 +239,7 @@ class TestDocumentModelDrivenMethod(BaseDocsTest):
             exclude_input=['Bar']
         )
         self.assert_contains_lines_in_order([
-            '.. py:method:: foo(Biz=None)',
+            '.. py:method:: foo(**kwargs)',
             '  This describes the foo method.',
             '  **Request Syntax**',
             '  ::',
@@ -275,7 +276,7 @@ class TestDocumentModelDrivenMethod(BaseDocsTest):
             exclude_output=['Bar']
         )
         self.assert_contains_lines_in_order([
-            '.. py:method:: foo(Bar=None, Biz=None)',
+            '.. py:method:: foo(**kwargs)',
             '  This describes the foo method.',
             '  **Request Syntax**',
             '  ::',
diff --git a/tests/unit/docs/test_paginator.py b/tests/unit/docs/test_paginator.py
index c528fc7d4..f2673e0fc 100644
--- a/tests/unit/docs/test_paginator.py
+++ b/tests/unit/docs/test_paginator.py
@@ -39,7 +39,7 @@ class TestPaginatorDocumenter(BaseDocsTest):
             '.. py:class:: MyService.Paginator.sample_operation',
             '  ::',
             '    paginator = client.get_paginator(\'sample_operation\')',
-            '  .. py:method:: paginate(Biz=None, PaginationConfig=None)',
+            '  .. py:method:: paginate(**kwargs)',
             ('    Creates an iterator that will paginate through responses'
              ' from :py:meth:`MyService.Client.sample_operation`.'),
             '    **Request Syntax**',
diff --git a/tests/unit/docs/test_service.py b/tests/unit/docs/test_service.py
index f76699c3f..f9b0a99ee 100644
--- a/tests/unit/docs/test_service.py
+++ b/tests/unit/docs/test_service.py
@@ -45,17 +45,17 @@ class TestServiceDocumenter(BaseDocsTest):
             '    client = session.create_client(\'myservice\')',
             '  These are the available methods:',
             '  *   :py:meth:`MyService.Client.sample_operation`',
-            '  .. py:method:: sample_operation(Biz=None)',
+            '  .. py:method:: sample_operation(**kwargs)',
             '==========',
             'Paginators',
             '==========',
             '.. py:class:: MyService.Paginator.sample_operation',
-            '  .. py:method:: paginate(Biz=None, PaginationConfig=None)',
+            '  .. py:method:: paginate(**kwargs)',
             '=======',
             'Waiters',
             '=======',
             '.. py:class:: MyService.Waiter.sample_operation_complete',
-            '  .. py:method:: wait(Biz=None)'
+            '  .. py:method:: wait(**kwargs)'
         ]
         for line in lines:
             self.assertIn(line, contents)
diff --git a/tests/unit/docs/test_waiter.py b/tests/unit/docs/test_waiter.py
index 7317d9542..64f04d31f 100644
--- a/tests/unit/docs/test_waiter.py
+++ b/tests/unit/docs/test_waiter.py
@@ -36,7 +36,7 @@ class TestWaiterDocumenter(BaseDocsTest):
             '.. py:class:: MyService.Waiter.sample_operation_complete',
             '  ::',
             '    waiter = client.get_waiter(\'sample_operation_complete\')',
-            '  .. py:method:: wait(Biz=None)',
+            '  .. py:method:: wait(**kwargs)',
             ('    This polls :py:meth:`MyService.Client.sample_operation` '
              'every 15 seconds until a successful state is reached. An error '
              'is returned after 40 failed checks.'),