Skip to content

feat: add support for python 3.13 #696

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Oct 15, 2024
1 change: 1 addition & 0 deletions .github/workflows/unittest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
exclude:
- option: "_wo_grpc"
python: 3.7
Expand Down
6 changes: 4 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ In order to add a feature:
documentation.

- The feature must work fully on the following CPython versions:
3.7, 3.8, 3.9, 3.10, 3.11 and 3.12 on both UNIX and Windows.
3.7, 3.8, 3.9, 3.10, 3.11, 3.12 and 3.13 on both UNIX and Windows.

- The feature must not add unnecessary dependencies (where
"unnecessary" is of course subjective, but new dependencies should
Expand Down Expand Up @@ -71,7 +71,7 @@ We use `nox <https://nox.readthedocs.io/en/latest/>`__ to instrument our tests.

- To run a single unit test::

$ nox -s unit-3.12 -- -k <name of test>
$ nox -s unit-3.13 -- -k <name of test>


.. note::
Expand Down Expand Up @@ -203,13 +203,15 @@ We support:
- `Python 3.10`_
- `Python 3.11`_
- `Python 3.12`_
- `Python 3.13`_

.. _Python 3.7: https://docs.python.org/3.7/
.. _Python 3.8: https://docs.python.org/3.8/
.. _Python 3.9: https://docs.python.org/3.9/
.. _Python 3.10: https://docs.python.org/3.10/
.. _Python 3.11: https://docs.python.org/3.11/
.. _Python 3.12: https://docs.python.org/3.12/
.. _Python 3.13: https://docs.python.org/3.13/


Supported versions can be found in our ``noxfile.py`` `config`_.
Expand Down
6 changes: 4 additions & 2 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# Black and flake8 clash on the syntax for ignoring flake8's F401 in this file.
BLACK_EXCLUDES = ["--exclude", "^/google/api_core/operations_v1/__init__.py"]

PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
PYTHON_VERSIONS = ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]

DEFAULT_PYTHON_VERSION = "3.10"
CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute()
Expand Down Expand Up @@ -95,7 +95,8 @@ def install_prerelease_dependencies(session, constraints_path):
prerel_deps = [
"google-auth",
"googleapis-common-protos",
"grpcio",
# Exclude grpcio!=1.67.0rc1 which does not support python 3.13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to disable the rc version? My assumption is that the latest stable version is installed by default.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this change, the pre-release test fails (See https://github.com/googleapis/python-api-core/actions/runs/11259852849/job/31309789274)

Do we need to disable the rc version? My assumption is that the latest stable version is installed by default.

We don't get the stable version in the prerelease_deps nox session. We get the latest pre-release which is https://pypi.org/project/grpcio/1.67.0rc1/. We're not disabling all rc versions, just 1.67.0rc1 which doesn't support python 3.13

"grpcio!=1.67.0rc1",
"grpcio-status",
"proto-plus",
"protobuf",
Expand Down Expand Up @@ -132,6 +133,7 @@ def default(session, install_grpc=True, prerelease=False, install_async_rest=Fal

install_extras = []
if install_grpc:
# Note: The extra is called `grpc` and not `grpcio`.
install_extras.append("grpc")

constraints_dir = str(CURRENT_DIRECTORY / "testing")
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Operating System :: OS Independent",
"Topic :: Internet",
],
Expand Down
Empty file added testing/constraints-3.13.txt
Empty file.
5 changes: 5 additions & 0 deletions tests/asyncio/retry/test_retry_streaming_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ async def test___call___generator_retry(self, sleep):
unpacked = [await generator.__anext__() for i in range(10)]
assert unpacked == [0, 1, 2, 0, 1, 2, 0, 1, 2, 0]
assert on_error.call_count == 3
await generator.aclose()

@mock.patch("random.uniform", autospec=True, side_effect=lambda m, n: n)
@mock.patch("asyncio.sleep", autospec=True)
Expand Down Expand Up @@ -246,6 +247,7 @@ async def _mock_send_gen():
recv = await generator.asend(msg)
out_messages.append(recv)
assert in_messages == out_messages
await generator.aclose()

@mock.patch("asyncio.sleep", autospec=True)
@pytest.mark.asyncio
Expand All @@ -263,6 +265,7 @@ async def test___call___generator_send_retry(self, sleep):
with pytest.raises(TypeError) as exc_info:
await generator.asend("cannot send to fresh generator")
assert exc_info.match("can't send non-None value")
await generator.aclose()

# error thrown on 3
# generator should contain 0, 1, 2 looping
Expand All @@ -271,6 +274,7 @@ async def test___call___generator_send_retry(self, sleep):
unpacked = [await generator.asend(i) for i in range(10)]
assert unpacked == [1, 2, 0, 1, 2, 0, 1, 2, 0, 1]
assert on_error.call_count == 3
await generator.aclose()

@mock.patch("asyncio.sleep", autospec=True)
@pytest.mark.asyncio
Expand Down Expand Up @@ -382,6 +386,7 @@ async def wrapper():
assert await retryable.asend("test") == 1
assert await retryable.asend("test2") == 2
assert await retryable.asend("test3") == 3
await retryable.aclose()

@pytest.mark.parametrize("awaitable_wrapped", [True, False])
@mock.patch("asyncio.sleep", autospec=True)
Expand Down
2 changes: 2 additions & 0 deletions tests/asyncio/test_page_iterator_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ async def test__page_aiter_increment(self):
await page_aiter.__anext__()

assert iterator.num_results == 1
await page_aiter.aclose()

@pytest.mark.asyncio
async def test__page_aiter_no_increment(self):
Expand All @@ -122,6 +123,7 @@ async def test__page_aiter_no_increment(self):

# results should still be 0 after fetching a page.
assert iterator.num_results == 0
await page_aiter.aclose()

@pytest.mark.asyncio
async def test__items_aiter(self):
Expand Down