From 474961aa62ec598f8aa658b92032f1843a507116 Mon Sep 17 00:00:00 2001 From: Anthonios Partheniou Date: Thu, 23 Nov 2023 14:32:01 -0500 Subject: [PATCH] feat: add support for python 3.12 (#153) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add support for python 3.12 * remove usage of datetime.datetime.utcnow * fix tests * fix tests * fix tests * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * update post processor image * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot --- .github/.OwlBot.lock.yaml | 4 +- .github/sync-repo-settings.yaml | 2 + .github/workflows/unittest.yml | 2 +- .kokoro/samples/python3.12/common.cfg | 40 +++++++++++++++++++ .kokoro/samples/python3.12/continuous.cfg | 6 +++ .kokoro/samples/python3.12/periodic-head.cfg | 11 +++++ .kokoro/samples/python3.12/periodic.cfg | 6 +++ .kokoro/samples/python3.12/presubmit.cfg | 6 +++ mypy.ini | 2 +- noxfile.py | 6 +-- setup.py | 17 +++++++- .../lower_bound_checker.py | 19 +++++---- test_utils/prefixer.py | 6 ++- testing/constraints-3.12.txt | 0 testing/constraints-3.6.txt | 4 -- testing/constraints-3.7.txt | 2 +- tests/unit/resources/bad_package/setup.py | 2 +- tests/unit/resources/good_package/setup.py | 2 +- tests/unit/test_prefixer.py | 2 +- 19 files changed, 113 insertions(+), 26 deletions(-) create mode 100644 .kokoro/samples/python3.12/common.cfg create mode 100644 .kokoro/samples/python3.12/continuous.cfg create mode 100644 .kokoro/samples/python3.12/periodic-head.cfg create mode 100644 .kokoro/samples/python3.12/periodic.cfg create mode 100644 .kokoro/samples/python3.12/presubmit.cfg create mode 100644 testing/constraints-3.12.txt delete mode 100644 testing/constraints-3.6.txt diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 453b540..eb4d9f7 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:caffe0a9277daeccc4d1de5c9b55ebba0901b57c2f713ec9c876b0d4ec064f61 -# created: 2023-11-08T19:46:45.022803742Z + digest: sha256:bacc3af03bff793a03add584537b36b5644342931ad989e3ba1171d3bd5399f5 +# created: 2023-11-23T18:17:28.105124211Z diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 0012af0..9efe66d 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -14,6 +14,8 @@ branchProtectionRules: - 'unit (3.8)' - 'unit (3.9)' - 'unit (3.10)' + - 'unit (3.11)' + - 'unit (3.12)' - 'cover' permissionRules: - team: actools-python diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index fd10b2c..8ed0352 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.kokoro/samples/python3.12/common.cfg b/.kokoro/samples/python3.12/common.cfg new file mode 100644 index 0000000..078e72d --- /dev/null +++ b/.kokoro/samples/python3.12/common.cfg @@ -0,0 +1,40 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Specify which tests to run +env_vars: { + key: "RUN_TESTS_SESSION" + value: "py-3.12" +} + +# Declare build specific Cloud project. +env_vars: { + key: "BUILD_SPECIFIC_GCLOUD_PROJECT" + value: "python-docs-samples-tests-312" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-test-utils/.kokoro/test-samples.sh" +} + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker" +} + +# Download secrets for samples +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples" + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Use the trampoline script to run in docker. +build_file: "python-test-utils/.kokoro/trampoline_v2.sh" \ No newline at end of file diff --git a/.kokoro/samples/python3.12/continuous.cfg b/.kokoro/samples/python3.12/continuous.cfg new file mode 100644 index 0000000..a1c8d97 --- /dev/null +++ b/.kokoro/samples/python3.12/continuous.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} \ No newline at end of file diff --git a/.kokoro/samples/python3.12/periodic-head.cfg b/.kokoro/samples/python3.12/periodic-head.cfg new file mode 100644 index 0000000..a36b71a --- /dev/null +++ b/.kokoro/samples/python3.12/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-test-utils/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.12/periodic.cfg b/.kokoro/samples/python3.12/periodic.cfg new file mode 100644 index 0000000..71cd1e5 --- /dev/null +++ b/.kokoro/samples/python3.12/periodic.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "False" +} diff --git a/.kokoro/samples/python3.12/presubmit.cfg b/.kokoro/samples/python3.12/presubmit.cfg new file mode 100644 index 0000000..a1c8d97 --- /dev/null +++ b/.kokoro/samples/python3.12/presubmit.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} \ No newline at end of file diff --git a/mypy.ini b/mypy.ini index 19d0802..8efb6f7 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,3 +1,3 @@ [mypy] -python_version = 3.6 +python_version = 3.9 exclude = tests/unit/resources/ diff --git a/noxfile.py b/noxfile.py index 5abd7a9..555f547 100644 --- a/noxfile.py +++ b/noxfile.py @@ -86,7 +86,7 @@ def mypy(session): session.run("mypy", "test_utils/", "tests/") -@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11"]) +@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]) def unit(session): constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" @@ -123,7 +123,7 @@ def check_lower_bounds(session): "--package-name", "google-cloud-testutils", "--constraints-file", - "testing/constraints-3.6.txt", + "testing/constraints-3.7.txt", ) @@ -137,5 +137,5 @@ def update_lower_bounds(session): "--package-name", "google-cloud-testutils", "--constraints-file", - "testing/constraints-3.6.txt", + "testing/constraints-3.7.txt", ) diff --git a/setup.py b/setup.py index 2c8b529..55a199c 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,12 @@ ["lower-bound-checker=test_utils.lower_bound_checker.lower_bound_checker:main"], ) +packages = [ + package + for package in setuptools.find_namespace_packages() + if package.startswith("test_utils") +] + setuptools.setup( name="google-cloud-testutils", version=version, @@ -36,11 +42,16 @@ author_email="googleapis-packages@google.com", license="Apache 2.0", url="https://github.com/googleapis/python-test-utils", - packages=setuptools.PEP420PackageFinder.find(), + packages=packages, entry_points={"console_scripts": scripts}, platforms="Posix; MacOS X; Windows", include_package_data=True, - install_requires=("google-auth >= 0.4.0", "click>=7.0.0", "packaging>=19.0"), + install_requires=( + "google-auth >= 0.4.0", + "click>=7.0.0", + "packaging>=19.0", + "importlib_metadata>=1.0.0; python_version<'3.8'", + ), python_requires=">=3.7", classifiers=[ "Development Status :: 4 - Beta", @@ -51,6 +62,8 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", ], diff --git a/test_utils/lower_bound_checker/lower_bound_checker.py b/test_utils/lower_bound_checker/lower_bound_checker.py index c51fd57..b6594de 100644 --- a/test_utils/lower_bound_checker/lower_bound_checker.py +++ b/test_utils/lower_bound_checker/lower_bound_checker.py @@ -12,13 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import click from pathlib import Path from typing import List, Tuple, Set +import sys -import click from packaging.requirements import Requirement from packaging.version import Version -import pkg_resources + +if sys.version_info < (3, 8): + import importlib_metadata as metadata +else: + import importlib.metadata as metadata def _get_package_requirements(package_name: str) -> List[Requirement]: @@ -30,12 +35,12 @@ def _get_package_requirements(package_name: str) -> List[Requirement]: package_name (str): The name of the package. Returns: - List[pkg_resources.Requirement]: A list of package requirements and extras. + List[packaging.requirements.Requirement]: A list of package requirements and extras. """ - dist = pkg_resources.get_distribution(package_name) - extras = tuple(dist.extras) - requirements = [Requirement(str(r)) for r in dist.requires(extras=extras)] - + requirements = [] + distribution = metadata.distribution(package_name) + if distribution.requires: + requirements = [Requirement(str(r)) for r in distribution.requires] return requirements diff --git a/test_utils/prefixer.py b/test_utils/prefixer.py index dd8c832..89d1e8e 100644 --- a/test_utils/prefixer.py +++ b/test_utils/prefixer.py @@ -58,7 +58,8 @@ def __init__( self._prefix = _common_prefix(repo, relative_dir, separator=separator) def create_prefix(self) -> str: - timestamp = datetime.datetime.utcnow().strftime(_RESOURCE_DATE_FORMAT) + now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None) + timestamp = now.strftime(_RESOURCE_DATE_FORMAT) random_string = hex(random.randrange(0x1000000))[2:] return f"{self._prefix}{self._separator}{timestamp}{self._separator}{random_string}" @@ -72,7 +73,8 @@ def _name_to_date(self, resource_name: str) -> Union[datetime.datetime, None]: return None def should_cleanup(self, resource_name: str) -> bool: - yesterday = datetime.datetime.utcnow() - self._cleanup_age + now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None) + yesterday = now - self._cleanup_age if not resource_name.startswith(self._prefix): return False diff --git a/testing/constraints-3.12.txt b/testing/constraints-3.12.txt new file mode 100644 index 0000000..e69de29 diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt deleted file mode 100644 index b0e36f6..0000000 --- a/testing/constraints-3.6.txt +++ /dev/null @@ -1,4 +0,0 @@ -click==7.0.0 -google-auth==0.4.0 -packaging==19.0 -colorlog==3.0.0 diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index b0e36f6..ed8f59f 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -1,4 +1,4 @@ click==7.0.0 google-auth==0.4.0 +importlib-metadata==1.0.0 packaging==19.0 -colorlog==3.0.0 diff --git a/tests/unit/resources/bad_package/setup.py b/tests/unit/resources/bad_package/setup.py index 3daa33d..86e7deb 100644 --- a/tests/unit/resources/bad_package/setup.py +++ b/tests/unit/resources/bad_package/setup.py @@ -36,5 +36,5 @@ ], install_requires=requirements, packages=setuptools.find_packages(), - python_requires=">=3.6", + python_requires=">=3.7", ) diff --git a/tests/unit/resources/good_package/setup.py b/tests/unit/resources/good_package/setup.py index 25c29ab..97c5cb2 100644 --- a/tests/unit/resources/good_package/setup.py +++ b/tests/unit/resources/good_package/setup.py @@ -42,5 +42,5 @@ install_requires=requirements, extras_require=extras, packages=setuptools.find_packages(), - python_requires=">=3.6", + python_requires=">=3.7", ) diff --git a/tests/unit/test_prefixer.py b/tests/unit/test_prefixer.py index aab1f5d..bfe2e8e 100644 --- a/tests/unit/test_prefixer.py +++ b/tests/unit/test_prefixer.py @@ -28,7 +28,7 @@ class FakeDateTime(object): def __init__(self, fake_now): self._fake_now = fake_now - def utcnow(self): + def now(self, timezone): return self._fake_now strptime = datetime.datetime.strptime