Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d2ccdf6
ci: remove Python 3.7 from run_single_test.sh
chalmerlowe May 1, 2026
09ad9e1
chore(templates): update python version in mypy.ini.j2 to 3.8
chalmerlowe May 1, 2026
ea3801e
docs(gapic-generator): update Python version in index.rst to 3.8+
chalmerlowe May 1, 2026
e57206d
docs(gapic-generator): update Python version in bazel.rst to 3.8+
chalmerlowe May 1, 2026
8279e27
docs(gapic-generator): update Python version in _verifying.rst to 3.8
chalmerlowe May 1, 2026
f377a01
chore(templates): update Python version requirement and clean up __in…
chalmerlowe May 1, 2026
042e3ef
chore(templates): update Python version requirement and clean up vers…
chalmerlowe May 1, 2026
e75c0f6
chore(gapic-generator): remove outdated comment in options.py
chalmerlowe May 1, 2026
0eb3b09
chore(gapic): update Python version requirement to 3.10 in setup.py a…
chalmerlowe May 1, 2026
830c66f
chore(gapic): use functools.cache instead of lru_cache in wrappers.py
chalmerlowe May 1, 2026
eb01050
chore(gapic): update Python version in setup and mypy templates
chalmerlowe May 1, 2026
9a6dece
chore(gapic): clean up Python version guards and imports in templates
chalmerlowe May 1, 2026
3f6a95c
ci: update Python version comment in run_conditional_tests.sh
chalmerlowe May 1, 2026
37f8f6a
chore(gapic): drop Python 3.8 and 3.9 from CI shell scripts
chalmerlowe May 1, 2026
9770d83
chore(gapic): remove Python 3.9 from generated noxfile templates
chalmerlowe May 1, 2026
8017018
chore(gapic): update target version in generator and clean up test ma…
chalmerlowe May 1, 2026
e7a2039
docs(gapic-generator): update Python version to 3.10 in getting-start…
chalmerlowe May 1, 2026
c4951de
chore(gapic): clean up imports in ads-templates test template
chalmerlowe May 1, 2026
8917093
chore(gapic): add ignore pragmas for false positives
chalmerlowe May 1, 2026
57281c3
chore(gapic): use ignore-next-line pragma in Dockerfile
chalmerlowe May 1, 2026
9ae1839
chore(gapic): remove Python 3.9 templates and update workflow matrix
chalmerlowe May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .generator/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ RUN unzip protoc-25.3-linux-x86_64.zip -d protoc

# Download/extract pandoc
# Pandoc is required by gapic-generator-python for parsing documentation
# version-scanner: ignore-next-line
ENV PANDOC_VERSION=3.8.2
RUN mkdir pandoc-binary
RUN wget https://github.com/jgm/pandoc/releases/download/${PANDOC_VERSION}/pandoc-${PANDOC_VERSION}-linux-amd64.tar.gz
Expand Down
2 changes: 1 addition & 1 deletion .generator/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ def _run_post_processor(output: str, library_id: str, is_mono_repo: bool):
# TODO(https://github.com/googleapis/google-cloud-python/issues/15538):
# Investigate if a `target_version needs to be maintained
# or can be eliminated.
target_version = "py39"
target_version = "py310"
common_args = [
f"--target-version={target_version}",
"--line-length=88",
Expand Down
2 changes: 1 addition & 1 deletion .generator/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ def test_run_individual_session_success(mocker, caplog, is_mono_repo):
"cli.subprocess.run", return_value=MagicMock(returncode=0)
)

test_session = "unit-3.9"
test_session = "unit-3.10"
test_library_id = "test-library"
repo = "repo"
_run_individual_session(test_session, test_library_id, repo, is_mono_repo)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gapic-generator-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ env:
SHOWCASE_VERSION: 0.35.0
PROTOC_VERSION: 3.20.2
LATEST_STABLE_PYTHON: 3.14
ALL_PYTHON: "['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']"
ALL_PYTHON: "['3.10', '3.11', '3.12', '3.13', '3.14']"

jobs:
check_changes:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ repos:
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
rev: 3.9.2 # version-scanner: ignore
hooks:
- id: flake8
2 changes: 1 addition & 1 deletion ci/run_conditional_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# `BUILD_TYPE` should be one of ["presubmit", "continuous"]
# `TEST_TYPE` should be one of ["docs", "docfx", "prerelease", "unit"]
# or match the name of the nox session that you want to run.
# `PY_VERSION` should be one of ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
# `PY_VERSION` should be one of ["3.10", "3.11", "3.12"]

# `TEST_TYPE` and `PY_VERSION` are required by the script `ci/run_single_test.sh`

Expand Down
14 changes: 1 addition & 13 deletions ci/run_single_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

# This script requires the following environment variables to be set:
# `TEST_TYPE` should be one of ["lint", "lint_setup_py", "docs", "docfx", "prerelease"]
# `PY_VERSION` should be one of ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
# `PY_VERSION` should be one of ["3.10", "3.11", "3.12", "3.13"]

# This script is called by the `ci/run_conditional_tests.sh` script.
# A specific `nox` session will be run, depending on the value of
Expand Down Expand Up @@ -70,18 +70,6 @@ case ${TEST_TYPE} in
;;
unit)
case ${PY_VERSION} in
"3.7")
nox -s unit-3.7
retval=$?
;;
"3.8")
nox -s unit-3.8
retval=$?
;;
"3.9")
nox -s unit-3.9
retval=$?
;;
"3.10")
nox -s unit-3.10
retval=$?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Create a virtual environment for the library:

.. code-block:: shell

$ virtualenv ~/.local/client-lib --python=`which python3.7`
$ virtualenv ~/.local/client-lib --python=`which python3.10`
$ source ~/.local/client-lib/bin/activate

Next, install the library:
Expand Down
2 changes: 1 addition & 1 deletion packages/gapic-generator/docs/getting-started/bazel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ install it is simply downloading the binary and making it executable:
Python and Dependencies
~~~~~~~~~~~~~~~~~~~~~~~
Bazel build is mostly hermetic, with a few exceptions for Python generator.
Specifically it expects Python 3.7+ with the python dev packages to be installed.
Specifically it expects Python 3.10+ with the python dev packages to be installed.

On Linux, to install those, simply run:

Expand Down
2 changes: 1 addition & 1 deletion packages/gapic-generator/docs/getting-started/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Getting Started
---------------

This code generator is implemented as a plugin to ``protoc``, the compiler
for `protocol buffers`_, and will run in any environment that Python 3.7+ and
for `protocol buffers`_, and will run in any environment that Python 3.10+ and
protocol buffers do.

It is recommended to install the tool locally and run it through ``protoc``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ from {{package_path}} import gapic_version as package_version
__version__ = package_version.__version__


if sys.version_info < (3, 7):
raise ImportError('This module requires Python 3.7 or later.')
if sys.version_info < (3, 10):
raise ImportError('This module requires Python 3.10 or later.')


_lazy_type_to_package_map = {
Expand All @@ -37,14 +37,14 @@ _lazy_type_to_package_map = {


# Background on how this behaves: https://www.python.org/dev/peps/pep-0562/
def __getattr__(name): # Requires Python >= 3.7
def __getattr__(name):
if name == '__all__':
all_names = globals()['__all__'] = sorted(_lazy_type_to_package_map)
return all_names
elif name in _lazy_type_to_package_map:
module = importlib.import_module(f'{_lazy_type_to_package_map[name]}')
klass = getattr(module, name)
{# new_klass = type(name, (klass,), {'__doc__': klass.__doc__}) #}

globals()[name] = klass
return klass
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import importlib
import sys


if sys.version_info < (3, 7):
raise ImportError('This module requires Python 3.7 or later.')
if sys.version_info < (3, 10):
raise ImportError('This module requires Python 3.10 or later.')


_lazy_type_to_package_map = {
Expand All @@ -30,14 +30,14 @@ _lazy_type_to_package_map = {


# Background on how this behaves: https://www.python.org/dev/peps/pep-0562/
def __getattr__(name): # Requires Python >= 3.7
def __getattr__(name):
if name == '__all__':
all_names = globals()['__all__'] = sorted(_lazy_type_to_package_map)
return all_names
elif name in _lazy_type_to_package_map:
module = importlib.import_module(f'{_lazy_type_to_package_map[name]}')
klass = getattr(module, name)
{# new_klass = type(name, (klass,), {'__doc__': klass.__doc__}) #}

globals()[name] = klass
return klass
else:
Expand Down
2 changes: 1 addition & 1 deletion packages/gapic-generator/gapic/ads-templates/mypy.ini.j2
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[mypy]
python_version = 3.7
python_version = 3.10
namespace_packages = True
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import nox # type: ignore
# Add tests for Python 3.15 alpha1
# https://peps.python.org/pep-0790/
ALL_PYTHON = [
"3.9",
"3.10",
"3.11",
"3.12",
Expand Down
3 changes: 1 addition & 2 deletions packages/gapic-generator/gapic/ads-templates/setup.py.j2
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ setuptools.setup(
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -75,7 +74,7 @@ setuptools.setup(
],
platforms="Posix; MacOS X; Windows",
packages=packages,
python_requires=">=3.9",
python_requires=">=3.10",
install_requires=dependencies,
include_package_data=True,
zip_safe=False,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@ import os
{% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|list %}
import re
{% endif %}
# try/except added for compatibility with python < 3.8
try:
from unittest import mock
from unittest.mock import AsyncMock # pragma: NO COVER
except ImportError: # pragma: NO COVER
import mock
from unittest import mock
from unittest.mock import AsyncMock

import grpc
from grpc.experimental import aio
Expand Down
10 changes: 2 additions & 8 deletions packages/gapic-generator/gapic/schema/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1284,19 +1284,13 @@ def _to_regex(self, path_template: str) -> Pattern:
return re.compile(f"^{self._convert_to_regex(path_template)}$")

# Use caching to avoid repeated computation
# TODO(https://github.com/googleapis/gapic-generator-python/issues/2161):
# Use `@functools.cache` instead of `@functools.lru_cache` once python 3.8 is dropped.
# https://docs.python.org/3/library/functools.html#functools.cache
@functools.lru_cache(maxsize=None)
@functools.cache
def to_regex(self) -> Pattern:
return self._to_regex(self.path_template)

@property
# Use caching to avoid repeated computation
# TODO(https://github.com/googleapis/gapic-generator-python/issues/2161):
# Use `@functools.cache` instead of `@functools.lru_cache` once python 3.8 is dropped.
# https://docs.python.org/3/library/functools.html#functools.cache
@functools.lru_cache(maxsize=None)
@functools.cache
def key(self) -> Union[str, None]:
if self.path_template == "":
return self.field
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ import sys

__version__ = package_version.__version__

if sys.version_info >= (3, 8): # pragma: NO COVER
from importlib import metadata
else: # pragma: NO COVER
# TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
# this code path once we drop support for Python 3.7
import importlib_metadata as metadata
from importlib import metadata

{# Import subpackages. -#}
{% for subpackage, _ in api.subpackages|dictsort %}
Expand Down Expand Up @@ -65,20 +60,12 @@ else: # pragma: NO COVER

_py_version_str = sys.version.split()[0]
_package_label = "{{package_path}}"
if sys.version_info < (3, 9):
if sys.version_info < (3, 10):
warnings.warn("You are using a non-supported Python version " +
f"({_py_version_str}). Google will not post any further " +
f"updates to {_package_label} supporting this Python version. " +
"Please upgrade to the latest Python version, or at " +
f"least to Python 3.9, and then update {_package_label}.",
FutureWarning)
if sys.version_info[:2] == (3, 9):
warnings.warn(f"You are using a Python version ({_py_version_str}) " +
f"which Google will stop supporting in {_package_label} in " +
"January 2026. Please " +
"upgrade to the latest Python version, or at " +
"least to Python 3.10, before then, and " +
f"then update {_package_label}.",
f"least to Python 3.10, and then update {_package_label}.",
FutureWarning)

def parse_version_to_tuple(version_string: str):
Expand Down
1 change: 0 additions & 1 deletion packages/gapic-generator/gapic/templates/noxfile.py.j2
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ if os.path.isdir("samples"):
LINT_PATHS.append("samples")

ALL_PYTHON = [
"3.9",
"3.10",
"3.11",
"3.12",
Expand Down
3 changes: 1 addition & 2 deletions packages/gapic-generator/gapic/templates/setup.py.j2
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ setuptools.setup(
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -100,7 +99,7 @@ setuptools.setup(
],
platforms="Posix; MacOS X; Windows",
packages=packages,
python_requires=">=3.9",
python_requires=">=3.10",
install_requires=dependencies,
extras_require=extras,
include_package_data=True,
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@ import os
{% if api.all_method_settings.values()|map(attribute="auto_populated_fields", default=[])|list %}
import re
{% endif %}
# try/except added for compatibility with python < 3.8
try:
from unittest import mock
from unittest.mock import AsyncMock # pragma: NO COVER
except ImportError: # pragma: NO COVER
import mock
from unittest import mock
from unittest.mock import AsyncMock

import grpc
from grpc.experimental import aio
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1005,9 +1005,7 @@ async def test_{{ method_name }}_async_pages():
{% endif %}
)
pages = []
# Workaround issue in python 3.9 related to code coverage by adding `# pragma: no branch`
# See https://github.com/googleapis/gapic-generator-python/pull/1174#issuecomment-1025132372
async for page_ in ( # pragma: no branch
async for page_ in (
await client.{{ method_name }}(request={})
).pages:
pages.append(page_)
Expand Down
2 changes: 1 addition & 1 deletion packages/gapic-generator/gapic/utils/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Options:
OPT_FLAGS: FrozenSet[str] = frozenset(
(
"add-iam-methods", # microgenerator implementation for `reroute_to_grpc_interface`
"lazy-import", # requires >= 3.7
"lazy-import",
"metadata", # generate GAPIC metadata JSON file
"old-naming", # TODO(dovs): Come up with a better comment
"retry-config", # takes a path
Expand Down
5 changes: 2 additions & 3 deletions packages/gapic-generator/noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
RUFF_EXCLUDES = "*golden*,*pb2.py,*pb2.pyi"

ALL_PYTHON = (
"3.9",
"3.10",
"3.11",
"3.12",
Expand Down Expand Up @@ -181,7 +180,7 @@ def fragment(session, use_ads_templates=False):
session.install("-e", ".")

# The specific failure is `Plugin output is unparseable`
if session.python in ("3.9", "3.10"):
if session.python == "3.10":
session.install("google-api-core<2.28")

frag_files = (
Expand Down Expand Up @@ -251,7 +250,7 @@ def showcase_library(
# Warnings emitted from google-api-core starting in 2.28
# appear to cause issues when running protoc.
# The specific failure is `Plugin output is unparseable`
if session.python in ("3.9", "3.10"):
if session.python == "3.10":
session.install("google-api-core<2.28")

# Install a client library for Showcase.
Expand Down
Loading
Loading