From fd1ef6e03252edca3641cc26ec227a00b4f44221 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Sun, 3 Dec 2023 06:05:39 -0500 Subject: [PATCH] feat: Introduce compatibility with native namespace packages (#260) * feat: Introduce compatibility with native namespace packages * lint * mypy * omit /tmp/ in coverage --- .coveragerc | 1 + google/__init__.py | 24 -------------------- google/cloud/__init__.py | 24 -------------------- google/cloud/obsolete/__init__.py | 11 ++++++--- noxfile.py | 2 +- owlbot.py | 2 +- setup.py | 12 ++++------ tests/unit/test_packaging.py | 37 +++++++++++++++++++++++++++++++ 8 files changed, 52 insertions(+), 61 deletions(-) delete mode 100644 google/__init__.py delete mode 100644 google/cloud/__init__.py create mode 100644 tests/unit/test_packaging.py diff --git a/.coveragerc b/.coveragerc index c6430d3..b6be3e3 100644 --- a/.coveragerc +++ b/.coveragerc @@ -3,6 +3,7 @@ branch = True [report] omit = + /tmp/* google/cloud/__init__.py google/cloud/_testing/__init__.py google/cloud/environment_vars/__init__.py diff --git a/google/__init__.py b/google/__init__.py deleted file mode 100644 index 70a7bd9..0000000 --- a/google/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2016 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. - -"""Google namespace package.""" - -try: - import pkg_resources - - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - - __path__ = pkgutil.extend_path(__path__, __name__) # type: ignore diff --git a/google/cloud/__init__.py b/google/cloud/__init__.py deleted file mode 100644 index ef78099..0000000 --- a/google/cloud/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2016 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. - -"""Google Cloud namespace package.""" - -try: - import pkg_resources - - pkg_resources.declare_namespace(__name__) -except ImportError: - import pkgutil - - __path__ = pkgutil.extend_path(__path__, __name__) # type: ignore diff --git a/google/cloud/obsolete/__init__.py b/google/cloud/obsolete/__init__.py index 99a83f9..854110e 100644 --- a/google/cloud/obsolete/__init__.py +++ b/google/cloud/obsolete/__init__.py @@ -14,9 +14,14 @@ """Helpers for deprecated code and modules.""" +import sys import warnings -import pkg_resources + +if sys.version_info < (3, 8): + import importlib_metadata as metadata +else: + import importlib.metadata as metadata def complain(distribution_name): @@ -29,7 +34,7 @@ def complain(distribution_name): distribution_name (str): The name of the obsolete distribution. """ try: - pkg_resources.get_distribution(distribution_name) + metadata.distribution(distribution_name) warnings.warn( "The {pkg} distribution is now obsolete. " "Please `pip uninstall {pkg}`. " @@ -38,5 +43,5 @@ def complain(distribution_name): ), DeprecationWarning, ) - except pkg_resources.DistributionNotFound: + except metadata.PackageNotFoundError: pass diff --git a/noxfile.py b/noxfile.py index 9836fcf..d84e4b9 100644 --- a/noxfile.py +++ b/noxfile.py @@ -48,7 +48,7 @@ def mypy(session): "types-mock", "types-protobuf", ) - session.run("mypy", "google", "tests") + session.run("mypy", "-p", "google", "-p", "tests") @nox.session(python=DEFAULT_PYTHON_VERSION) diff --git a/owlbot.py b/owlbot.py index 1006250..69af86f 100644 --- a/owlbot.py +++ b/owlbot.py @@ -35,7 +35,7 @@ ".flake8", ".coveragerc", "setup.cfg", - "README.rst", + "README.rst", ], ) diff --git a/setup.py b/setup.py index 06852b8..a6c51c3 100644 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ dependencies = [ "google-api-core >= 1.31.6, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0", "google-auth >= 1.25.0, < 3.0dev", + "importlib-metadata > 1.0.0; python_version<'3.8'", ] extras = {"grpc": "grpcio >= 1.38.0, < 2.0dev"} @@ -50,15 +51,11 @@ # Only include packages under the 'google' namespace. Do not include tests, # benchmarks, etc. packages = [ - package for package in setuptools.find_packages() if package.startswith("google") + package + for package in setuptools.find_namespace_packages() + if package.startswith("google") ] -# Determine which namespaces are needed. -namespaces = ["google"] -if "google.cloud" in packages: - namespaces.append("google.cloud") - - setuptools.setup( name=name, version=version, @@ -83,7 +80,6 @@ ], platforms="Posix; MacOS X; Windows", packages=packages, - namespace_packages=namespaces, install_requires=dependencies, extras_require=extras, python_requires=">=3.7", diff --git a/tests/unit/test_packaging.py b/tests/unit/test_packaging.py new file mode 100644 index 0000000..e931116 --- /dev/null +++ b/tests/unit/test_packaging.py @@ -0,0 +1,37 @@ +# 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 ``google-cloud-core``. + 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 ``google-cloud-core``. + 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)