Repository: googleapis/google-cloud-python

Issue:
API Core PyType fails intermittently/changing errors
https://github.com/googleapis/google-cloud-python/pull/6769

Copying from #6769 and @rchen152 


> @crwilcox It looks like what's happening is that pytype is somehow finding multiple files named path_template.py (and timeout.py and grpc_helpers.py - the error probably differs because it varies which file pytype discovers first). The other thing I noticed is that the file count in the status message ("Analyzing 53 sources with 0 dependencies") differs from the one I see (28 sources). Any idea why there might be two copies of some source files?
> 
> EDIT: if there are two files with the same name in different directories, this may be google/pytype#198.


Discussion:
One possible issue is not cleaning up the pytype output folder between runs.
I tried running the pytype test again, with and without removing `pytype_output` between runs, and I still can't reproduce the intermittent/changing errors. (There is a consistent pytype error in `iam.py`.)
The steps I'm taking are:
```
virtualenv --python=python3.6 .venv3
source .venv3/bin/activate
cd google-cloud-python/api_core/
pip install nox
nox -s pytype
```
Does this match how you're running pytype?
@rchen You shouldn't need to create a separate virtualenv:  `nox` does that for you when you run `nox -s pytype`.  I get errors (but not all for the same module) whether or not I remove the `pytype_output` directory before running it.  They all look like:

```bash
$ nox -re pytype
nox > Running session pytype
nox > Re-using existing virtualenv at /home/tseaver/projects/agendaless/Google/src/gcp/api_core/.nox/pytype.
nox > pip install --upgrade . grpcio >= 1.8.2 grpcio-gcp >= 0.2.2 pytype >= 2018.9.26
nox > pytype 
Analyzing 53 sources with 0 dependencies
ninja: Entering directory `.../api_core/pytype_output'
ninja: error: build.ninja:20: multiple rules generate .../api_core/pytype_output/pyi/google/api_core/general_helpers.pyi [-w dupbuild=err]
```

but the module / file varies from run to run.
I believe the error responsible for the "multiple rules generate" warning is in [`setup.cfg`](https://github.com/googleapis/google-cloud-python/blob/7a15ffc1834c4136305256f25e71975fcf18aa4a/api_core/setup.cfg#L4-L9).  We should be limiting inputs to the `google/` directory.
When I edit `setup.cfg` to include only `google/`, then I see the following error:

```bash
$ nox -re pytype
nox > Running session pytype
nox > Re-using existing virtualenv at .../api_core/.nox/pytype.
nox > pip install --upgrade . grpcio >= 1.8.2 grpcio-gcp >= 0.2.2 pytype >= 2018.9.26
nox > pytype 
Analyzing 26 sources with 0 dependencies
ninja: Entering directory `.../api_core/pytype_output'
[3/26] pytype-single --imports_info /h..._core/google/api_core/path_template.py
FAILED: .../api_core/pytype_output/pyi/google/api_core/iam.pyi 
pytype-single --imports_info .../api_core/pytype_output/imports/google.api_core.iam.imports --module-name google.api_core.iam -V 3.6 -o .../api_core/pytype_output/pyi/google/api_core/iam.pyi --analyze-annotated --nofail --quick .../api_core/google/api_core/iam.py
File ".../api_core/google/api_core/iam.py", line 248, in <module>: No attribute 'register' on Type[MutableMapping] [attribute-error]

For more details, see https://github.com/google/pytype/blob/master/docs/errors.md#attribute-error.
[26/26] pytype-single --imports_info /...gle/api_core/operations_v1/__init__.py
ninja: build stopped: cannot make progress due to previous errors.
nox > Command pytype  failed with exit code 1
nox > Session pytype failed.
```

I don't understand the error: `collections.abc.MutableMapping` clearly has a `register` method:  it [calls it on the `dict` type in its own source code](https://github.com/python/cpython/blob/1133a8c0efabf6b33a169039cf6e2e03bfe6cfe3/Lib/_collections_abc.py#L859).
OTOH, I think the call to `register` is spurious:  the `Policy` class already derives from `MutableMapping`.

Resolving patch:
diff --git a/api_core/google/api_core/iam.py b/api_core/google/api_core/iam.py
--- a/api_core/google/api_core/iam.py
+++ b/api_core/google/api_core/iam.py
@@ -243,6 +243,3 @@ def to_api_repr(self):
                 del resource["bindings"]
 
         return resource
-
-
-collections_abc.MutableMapping.register(Policy)


Test patch:
diff --git a/api_core/tests/unit/test_iam.py b/api_core/tests/unit/test_iam.py
--- a/api_core/tests/unit/test_iam.py
+++ b/api_core/tests/unit/test_iam.py
@@ -90,9 +90,12 @@ def test_owners_setter(self):
         MEMBER = "user:phred@example.com"
         expected = set([MEMBER])
         policy = self._make_one()
-        with warnings.catch_warnings():
-            warnings.simplefilter("always")
+
+        with warnings.catch_warnings(record=True) as warned:
             policy.owners = [MEMBER]
+
+        warning, = warned
+        assert warning.category is DeprecationWarning
         assert policy[OWNER_ROLE] == expected
 
     def test_editors_getter(self):
@@ -111,9 +114,12 @@ def test_editors_setter(self):
         MEMBER = "user:phred@example.com"
         expected = set([MEMBER])
         policy = self._make_one()
-        with warnings.catch_warnings():
-            warnings.simplefilter("always")
+
+        with warnings.catch_warnings(record=True) as warned:
             policy.editors = [MEMBER]
+
+        warning, = warned
+        assert warning.category is DeprecationWarning
         assert policy[EDITOR_ROLE] == expected
 
     def test_viewers_getter(self):
@@ -132,9 +138,12 @@ def test_viewers_setter(self):
         MEMBER = "user:phred@example.com"
         expected = set([MEMBER])
         policy = self._make_one()
-        with warnings.catch_warnings():
-            warnings.simplefilter("always")
+
+        with warnings.catch_warnings(record=True) as warned:
             policy.viewers = [MEMBER]
+
+        warning, = warned
+        assert warning.category is DeprecationWarning
         assert policy[VIEWER_ROLE] == expected
 
     def test_user(self):
@@ -240,17 +249,20 @@ def test_to_api_repr_binding_wo_members(self):
         assert policy.to_api_repr() == {}
 
     def test_to_api_repr_binding_w_duplicates(self):
+        import warnings
         from google.api_core.iam import OWNER_ROLE
 
         OWNER = "group:cloud-logs@google.com"
         policy = self._make_one()
-        policy.owners = [OWNER, OWNER]
+        with warnings.catch_warnings(record=True):
+            policy.owners = [OWNER, OWNER]
         assert policy.to_api_repr() == {
             "bindings": [{"role": OWNER_ROLE, "members": [OWNER]}]
         }
 
     def test_to_api_repr_full(self):
         import operator
+        import warnings
         from google.api_core.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE
 
         OWNER1 = "group:cloud-logs@google.com"
@@ -265,9 +277,10 @@ def test_to_api_repr_full(self):
             {"role": VIEWER_ROLE, "members": [VIEWER1, VIEWER2]},
         ]
         policy = self._make_one("DEADBEEF", 17)
-        policy.owners = [OWNER1, OWNER2]
-        policy.editors = [EDITOR1, EDITOR2]
-        policy.viewers = [VIEWER1, VIEWER2]
+        with warnings.catch_warnings(record=True):
+            policy.owners = [OWNER1, OWNER2]
+            policy.editors = [EDITOR1, EDITOR2]
+            policy.viewers = [VIEWER1, VIEWER2]
         resource = policy.to_api_repr()
         assert resource["etag"] == "DEADBEEF"
         assert resource["version"] == 17