Repository: googleapis/google-cloud-python

Issue:
Pub/Sub: return type`future` is not `concurrent.futures.Future` 
https://github.com/googleapis/google-cloud-python/blob/8f63393a151a22018a3d03c7a35576da25ee17b3/pubsub/google/cloud/pubsub_v1/publisher/client.py#L170

Contrary to what's in the [reference](https://gcloud-python.readthedocs.io/en/latest/pubsub/publisher/api/client.html#google.cloud.pubsub_v1.publisher.client.Client.publish), the correct return type for `publish()` should be `google.cloud.pubsub_v1.publisher.futures.Future`. I didn't find a reference for it but only some reference for [`google.cloud.pubsub_v1.subscriber.futures.StreamingPullFuture`](https://google-cloud.readthedocs.io/en/latest/pubsub/subscriber/api/futures.html). 

People won't be able to use of Python's concurrent library's `wait()` method on `google.cloud.pubsub_v1.publisher.futures.Future`. But our doc implies they can because we say the return type is `concurrent.futures.Future`.  

```Python
from concurrent.futures import wait
from google.cloud import pubsub_v1

publisher = pubsub_v1.PublisherClient()
# future has type `google.cloud.pubsub_v1.publisher.futures.Future`
future = publisher.publish('projects/{PROJECT_ID}/topics/{TOPIC_NAME}', data=b'rain')

# wait(fs, timeout=None, return_when='ALL_COMPLETED') expects a sequence of `concurrent.futures.Future`.  
wait([future])
```
Here is the error: 
```Python
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.5/concurrent/futures/_base.py", line 257, in wait
    with _AcquireFutures(fs):
  File "/usr/lib/python3.5/concurrent/futures/_base.py", line 146, in __enter__
    future._condition.acquire()
AttributeError: 'Future' object has no attribute '_condition'
```
I tried in both Python 2 and 3. 


Discussion:
@theacodes can you comment?
Yeah we should update it. It should additionally say that it conforms to the `concurrent.futures.Future` interface and can be used in similar ways, but it not completely compatible with `concurrent.futures` tools such as `wait()`.
Thanks! Listing a couple of places in the doc where publisher`future` is mentioned: 

1. https://google-cloud.readthedocs.io/en/latest/pubsub/publisher/api/client.html#google.cloud.pubsub_v1.publisher.client.Client.publish

2. https://google-cloud.readthedocs.io/en/latest/pubsub/publisher/index.html#futures
I have actually got another case where the returned future not being a `concurrent.futures.Future` hurts: asyncio in the standard library has some utilities for using blocking futures together with asyncio async futures, like [`asyncio.wrap_future`](https://docs.python.org/3/library/asyncio-future.html#asyncio.wrap_future), which check on `isinstance(f, concurrent.futures.Future)` to distinguish the future types. 
I currently have to resort to monkeypatching the base classes list of `google.cloud.pubsub_v1.publisher.futures.Future` to make it pass the checks, and the method itself works fine. If actually using/inheriting from `concurrent.futures.Future` is not possible, can at least some utilities for working together with asyncio be provided together with the custom future implementation?
@himikof we can't inherit from concurent.futures.Future because it brings in a ton of stuff. I'm happy for us to add utilities to make working across this stuff possible. It would be relatively low priority for us right now, but we would more than welcome contributions to get it done sooner.

Thanks!

Resolving patch:
diff --git a/pubsub/google/cloud/pubsub_v1/publisher/client.py b/pubsub/google/cloud/pubsub_v1/publisher/client.py
--- a/pubsub/google/cloud/pubsub_v1/publisher/client.py
+++ b/pubsub/google/cloud/pubsub_v1/publisher/client.py
@@ -196,8 +196,9 @@ def publish(self, topic, data, **attrs):
                 sent as metadata. (These may be text strings or byte strings.)
 
         Returns:
-            ~concurrent.futures.Future: An object conforming to the
-            ``concurrent.futures.Future`` interface.
+            ~google.api_core.future.Future: An object conforming to the
+            ``concurrent.futures.Future`` interface (but not an instance
+            of that class).
         """
         # Sanity check: Is the data being sent as a bytestring?
         # If it is literally anything else, complain loudly about it.


Test patch: