Repository: googleapis/google-cloud-python

Issue:
Pub/Sub doc: missing definition for `max_lease_duration` in FlowControl
The ref doc for [`max_lease_duration`](https://googleapis.github.io/google-cloud-python/latest/pubsub/types.html#google.cloud.pubsub_v1.types.FlowControl.max_lease_duration) does not describe what it is or how it is used, especially about how it interacts with ack deadlines. 

Given that this is an important config setting for long-running tasks, we may want to provide more documentation here by showing its default value (is it 2 hours), and explaining whether max lease duration restrains ack deadline modification or ack deadline modification overwrites max lease duration when one configures both flow control settings and ack deadlines. 


Discussion:
@tseaver How can we bring the default values (mentioned [here](https://github.com/googleapis/google-cloud-python/blob/414f0261d74b38756ff5300112915b537bf2b8dd/pubsub/google/cloud/pubsub_v1/types.py#L64)) into the documentation? 
@anguillanneuf `FlowControl` is a [Python `namedtuple`](https://docs.python.org/2/library/collections.html#collections.namedtuple), which provides no way to inject any additional semantic information into its docstring, or those of its members.  We could generate a class derived from the named tuple, and put proto-a comment-based docstring, but we would still not be able to tweak docstrings for the members.
@crwilcox @sduskis Surfacing this for your attention. 
**Edit:**
Oh, checked [#2634](https://github.com/googleapis/gapic-generator/issues/2634) - are we talking about namedtuples whose declarations are autogenerated from something else? In that case, it's the generator that would have to grab the comments from "something else" and inject them into the generated namedtuple declaration ... oh well.
(the proposal below would persistently work just for the namedtuples manually defined by a human).

---

In Python 3.5+ the docstrings of namedtuples and their members [can be updated](https://docs.python.org/3/whatsnew/3.5.html#collections):

```py
from collections import namedtuple

FlowControl = namedtuple("FlowControl", ["foo", "bar"])                                                                                                                                                                                                                  
FlowControl.__doc__ = "These are the flow control settings."                                                                                                                                                                                                                 
FlowControl.foo.__doc__ = "The foo setting does X"                                                                                                                                                                                                                       
FlowControl.bar.__doc__ = "The bar setting does Y"  
```

With the modifications, invoking `help(FlowControl)` displays the following (abbreviated):
```
Help on class FlowControl in module __main__:

class FlowControl(builtins.tuple)
 |  FlowControl(foo, bar)
 |  
 |  These are the flow control settings.
 |  
 |  Method resolution order:
 |      ...
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  foo
 |      The foo setting does X
 |  
 |  bar
 |      The bar setting does Y
 |  
 | ...
```
No more default _"Alias for field number X"_ descriptions of the members that end up in the linked docs. :tada: 

In the code, we could optionally modify the namedtuples' docstrings if Python version >= 3.5, and [generate the docs](https://github.com/googleapis/google-cloud-python/blob/master/CONTRIBUTING.rst#documentation-coverage-and-building-html-documentation) using one of the officially supported Python versions (which are, in fact, Python 3.5+).

Would that solve the issue, or am I missing something?
@plamut, It sounds like your solution would work.  Please do it.
@sduskis The `FlowControl` settings class is auto-generated, thus the change needs to be done in the code generator (the ticket that Tres linked above).

If Luke (the current assignee) is too occupied with other work, I can help, although I would first have to familiarize myself with the `gapic-generator` lib.
oh.  Thanks for the info @plamut.   That sounds like a time intensive change, so I don't think that the effort is advisable in the near term. @anguillanneuf, I'm ok keeping this open, but this will be a very low priority.

Resolving patch:
diff --git a/pubsub/google/cloud/pubsub_v1/types.py b/pubsub/google/cloud/pubsub_v1/types.py
--- a/pubsub/google/cloud/pubsub_v1/types.py
+++ b/pubsub/google/cloud/pubsub_v1/types.py
@@ -71,6 +71,38 @@
     2 * 60 * 60,  # max_lease_duration: 2 hours.
 )
 
+if sys.version_info >= (3, 5):
+    FlowControl.__doc__ = (
+        "The settings for controlling the rate at which messages are pulled "
+        "with an asynchronous subscription."
+    )
+    FlowControl.max_bytes.__doc__ = (
+        "The maximum total size of received - but not yet processed - messages "
+        "before pausing the message stream."
+    )
+    FlowControl.max_messages.__doc__ = (
+        "The maximum number of received - but not yet processed - messages before "
+        "pausing the message stream."
+    )
+    FlowControl.resume_threshold.__doc__ = (
+        "The relative threshold of the ``max_bytes`` and ``max_messages`` limits "
+        "below which to resume the message stream. Must be a positive number not "
+        "greater than ``1.0``."
+    )
+    FlowControl.max_requests.__doc__ = "Currently not in use."
+    FlowControl.max_request_batch_size.__doc__ = (
+        "The maximum number of requests scheduled by callbacks to process and "
+        "dispatch at a time."
+    )
+    FlowControl.max_request_batch_latency.__doc__ = (
+        "The maximum amount of time in seconds to wait for additional request "
+        "items before processing the next batch of requests."
+    )
+    FlowControl.max_lease_duration.__doc__ = (
+        "The maximum amount of time in seconds to hold a lease on a message "
+        "before dropping it from the lease management."
+    )
+
 
 _shared_modules = [
     http_pb2,
diff --git a/pubsub/synth.py b/pubsub/synth.py
--- a/pubsub/synth.py
+++ b/pubsub/synth.py
@@ -15,6 +15,7 @@
 """This script is used to synthesize generated parts of this library."""
 
 import re
+import textwrap
 
 import synthtool as s
 from synthtool import gcp
@@ -166,6 +167,48 @@ def _merge_dict(d1, d2):
     """
 )
 
+# document FlowControl settings in Python 3.5+
+s.replace(
+    "google/cloud/pubsub_v1/types.py",
+    "FlowControl.__new__.__defaults__ = \(.*?\)",
+    textwrap.dedent("""\
+    \g<0>
+
+    if sys.version_info >= (3, 5):
+        FlowControl.__doc__ = (
+            "The settings for controlling the rate at which messages are pulled "
+            "with an asynchronous subscription."
+        )
+        FlowControl.max_bytes.__doc__ = (
+            "The maximum total size of received - but not yet processed - messages "
+            "before pausing the message stream."
+        )
+        FlowControl.max_messages.__doc__ = (
+            "The maximum number of received - but not yet processed - messages before "
+            "pausing the message stream."
+        )
+        FlowControl.resume_threshold.__doc__ = (
+            "The relative threshold of the ``max_bytes`` and ``max_messages`` limits "
+            "below which to resume the message stream. Must be a positive number not "
+            "greater than ``1.0``."
+        )
+        FlowControl.max_requests.__doc__ = "Currently not in use."
+        FlowControl.max_request_batch_size.__doc__ = (
+            "The maximum number of requests scheduled by callbacks to process and "
+            "dispatch at a time."
+        )
+        FlowControl.max_request_batch_latency.__doc__ = (
+            "The maximum amount of time in seconds to wait for additional request "
+            "items before processing the next batch of requests."
+        )
+        FlowControl.max_lease_duration.__doc__ = (
+            "The maximum amount of time in seconds to hold a lease on a message "
+            "before dropping it from the lease management."
+        )
+    """),
+    flags=re.DOTALL,
+)
+
 # ----------------------------------------------------------------------------
 # Add templated files
 # ----------------------------------------------------------------------------


Test patch: