Repository: googleapis/python-api-common-protos

Issue:
Deprecated use of pkg_resources.declare_namespace
When using googleapis-common-protos, the following deprecated warning is issued:

```
    /.venv/lib/python3.9/site-packages/google/rpc/__init__.py:20: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google.rpc')`.
  Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages
    pkg_resources.declare_namespace(__name__)
```

The offending code shows up in a couple places:

https://github.com/googleapis/python-api-common-protos/blob/78138cc66635cffd239820e1d33b6d364ab118c7/google/rpc/__init__.py#L20
https://github.com/googleapis/python-api-common-protos/blob/78138cc66635cffd239820e1d33b6d364ab118c7/google/logging/__init__.py#L20

This issue is related to https://github.com/googleapis/python-api-common-protos/issues/140 and was reported in a comment (https://github.com/googleapis/python-api-common-protos/issues/140#issuecomment-1431044543) but I thought it might've been better to break it out into a separate issue for users to track. 

Discussion:

Patch:
diff --git a/google/api/__init__.py b/google/api/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/google/gapic/metadata/__init__.py b/google/gapic/metadata/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/google/logging/__init__.py b/google/logging/__init__.py
deleted file mode 100644
index 9a1b64a..0000000
--- a/google/logging/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-try:
-    import pkg_resources
-
-    pkg_resources.declare_namespace(__name__)
-except ImportError:
-    import pkgutil
-
-    __path__ = pkgutil.extend_path(__path__, __name__)
diff --git a/google/logging/type/__init__.py b/google/logging/type/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/google/longrunning/__init__.py b/google/longrunning/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/google/rpc/__init__.py b/google/rpc/__init__.py
deleted file mode 100644
index 9a1b64a..0000000
--- a/google/rpc/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-try:
-    import pkg_resources
-
-    pkg_resources.declare_namespace(__name__)
-except ImportError:
-    import pkgutil
-
-    __path__ = pkgutil.extend_path(__path__, __name__)
diff --git a/google/rpc/context/__init__.py b/google/rpc/context/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/google/type/__init__.py b/google/type/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/setup.py b/setup.py
index e698295..596466c 100644
--- a/setup.py
+++ b/setup.py
@@ -16,6 +16,7 @@ import io
 import os
 
 import setuptools
+from setuptools import find_namespace_packages
 
 
 name = "googleapis-common-protos"
@@ -36,12 +37,6 @@ readme_filename = os.path.join(package_root, "README.rst")
 with io.open(readme_filename, encoding="utf-8") as readme_file:
     readme = readme_file.read()
 
-packages = [
-    package
-    for package in setuptools.PEP420PackageFinder.find()
-    if package.startswith("google")
-]
-
 setuptools.setup(
     name=name,
     version=version,
@@ -66,10 +61,9 @@ setuptools.setup(
     install_requires=dependencies,
     extras_require=extras_require,
     license="Apache-2.0",
-    packages=packages,
     package_data={"": ["*.proto"]},
     python_requires=">=3.7",
-    namespace_packages=["google", "google.logging"],
+    packages=find_namespace_packages(exclude=("tests*", "testing*")),
     url="https://github.com/googleapis/python-api-common-protos",
     include_package_data=True,
 )


Test patch:
diff --git a/tests/unit/test_packaging.py b/tests/unit/test_packaging.py
new file mode 100644
index 0000000..f1ab3ff
--- /dev/null
+++ b/tests/unit/test_packaging.py
@@ -0,0 +1,52 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import subprocess
+import sys
+
+
+def test_namespace_package_compat(tmp_path):
+    """
+    The ``google`` namespace package should not be masked
+    by the presence of ``googleapis-common-protos``.
+    """
+    google = tmp_path / "google"
+    google.mkdir()
+    google.joinpath("othermod.py").write_text("")
+    env = dict(os.environ, PYTHONPATH=str(tmp_path))
+    cmd = [sys.executable, "-m", "google.othermod"]
+    subprocess.check_call(cmd, env=env)
+
+    """
+    The ``google.cloud`` namespace package should not be masked
+    by the presence of ``googleapis-common-protos``.
+    """
+    google_cloud = tmp_path / "google/cloud"
+    google_cloud.mkdir()
+    google_cloud.joinpath("othermod.py").write_text("")
+    env = dict(os.environ, PYTHONPATH=str(tmp_path))
+    cmd = [sys.executable, "-m", "google.cloud.othermod"]
+    subprocess.check_call(cmd, env=env)
+
+    """
+    The ``google.logging`` namespace package should not be masked
+    by the presence of ``googleapis-common-protos``.
+    """
+    google_logging = tmp_path / "google/logging"
+    google_logging.mkdir()
+    google_logging.joinpath("othermod.py").write_text("")
+    env = dict(os.environ, PYTHONPATH=str(tmp_path))
+    cmd = [sys.executable, "-m", "google.logging.othermod"]
+    subprocess.check_call(cmd, env=env)