Skip to content
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

Drop support for Python 3.8 #2500

Merged
merged 7 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 23 additions & 5 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
strategy:
fail-fast: false # run all variants across python versions/os to completion
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
os: ["ubuntu-20.04"]
proto-version: ["latest"]
include:
Expand All @@ -38,7 +38,7 @@ jobs:
python-version: "3.10"
proto-version: "latest"
- os: "ubuntu-20.04"
python-version: "3.8"
python-version: "3.9"
proto-version: "3.19"

runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -77,11 +77,23 @@ jobs:
timeout-minutes: 4
strategy:
matrix:
image-builder-version: ["2024.04", "2024.10"]
python-version: ["3.8", "3.13"]
include:
- image-builder-version: "2024.04"
python-version: "3.9"
- image-builder-version: "2024.04"
python-version: "3.12"
- image-builder-version: "2024.10"
python-version: "3.9"
- image-builder-version: "2024.10"
python-version: "3.13"

steps:
- uses: actions/checkout@v3

- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
Comment on lines +93 to +95
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whoops, we were always running this check on 3.8 anyway...


- name: Install dependencies
run: |
pip install -r modal/requirements/${{ matrix.image-builder-version }}.txt
Expand All @@ -91,7 +103,13 @@ jobs:
run: |
python -m venv venv
source venv/bin/activate
pip install grpcio-tools==1.59.2 grpclib==0.4.7
if [ "${{ matrix.python-version }}" == "3.9" ]; then
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Our published package has the same generated protos regardless of the python version of the client that ends up using it right? So maybe this should use the same python and versions as we do when publishing? (a bit messy to switch versions etc, but relatively easy with uv as a python manager)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This check is just meant to assert that we haven't added any third-party dependencies to python -m modal._container_entrypoint that aren't in the expected container requirements, so the specific way that we compile the protos isn't super important because whatever choice we make wouldn't introduce transitive dependencies. But (as we're discussing on Slack) there definitely are larger and trickier questions about our proto packaging!

pip install grpcio-tools==1.48.2 grpclib==0.4.7;
elif [ "${{ matrix.python-version }}" == "3.12" ]; then
pip install grpcio-tools==1.59.2 grpclib==0.4.7;
elif [ "${{ matrix.python-version }}" == "3.13" ]; then
pip install grpcio-tools==1.66.2 grpclib==0.4.7;
fi
python -m grpc_tools.protoc --python_out=. --grpclib_python_out=. --grpc_python_out=. -I . modal_proto/api.proto modal_proto/options.proto
python -m grpc_tools.protoc --plugin=protoc-gen-modal-grpclib-python=protoc_plugin/plugin.py --modal-grpclib-python_out=. -I . modal_proto/api.proto modal_proto/options.proto
deactivate
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ a [user guide](https://modal.com/docs/guide), and the detailed

## Installation

**This library requires Python 3.8 – 3.13.**
**This library requires Python 3.9 – 3.13.**

Install the package with `pip`:

Expand Down
4 changes: 2 additions & 2 deletions modal/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Copyright Modal Labs 2022
import sys

if sys.version_info[:2] < (3, 8):
raise RuntimeError("This version of Modal requires at least Python 3.8")
if sys.version_info[:2] < (3, 9):
raise RuntimeError("This version of Modal requires at least Python 3.9")
if sys.version_info[:2] >= (3, 14):
raise RuntimeError("This version of Modal does not support Python 3.14+")

Expand Down
7 changes: 0 additions & 7 deletions modal/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ def main():
setup_rich_traceback()
highlight_modal_deprecation_warnings()

if sys.version_info[:2] == (3, 8):
from .exception import deprecation_warning

deprecation_warning(
(2024, 5, 2), "Modal will soon drop support for Python 3.8.", show_source=False, pending=True
)

try:
entrypoint_cli()

Expand Down
10 changes: 1 addition & 9 deletions modal/_container_entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
from .client import Client, _Client
from .cls import Cls, Obj
from .config import logger
from .exception import ExecutionError, InputCancellation, InvalidError, deprecation_warning
from .exception import ExecutionError, InputCancellation, InvalidError
from .execution_context import _set_current_context_ids
from .functions import Function, _Function
from .partial_function import (
Expand Down Expand Up @@ -905,14 +905,6 @@ def breakpoint_wrapper():
if __name__ == "__main__":
logger.debug("Container: starting")

# Check and warn on deprecated Python version
if sys.version_info[:2] == (3, 8):
msg = (
"You are using Python 3.8 in your remote environment. Modal will soon drop support for this version,"
" and you will be unable to use this Image. Please update your Image definition."
)
deprecation_warning((2024, 5, 2), msg, show_source=False, pending=True)

container_args = api_pb2.ContainerArguments()
container_args.ParseFromString(base64.b64decode(sys.argv[1]))

Expand Down
14 changes: 6 additions & 8 deletions modal/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@
# Python versions in mount.py where we specify the "standalone Python versions" we create mounts for.
# Consider consolidating these multiple sources of truth?
SUPPORTED_PYTHON_SERIES: Dict[ImageBuilderVersion, List[str]] = {
"2024.10": ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"],
"2024.04": ["3.8", "3.9", "3.10", "3.11", "3.12"],
"2023.12": ["3.8", "3.9", "3.10", "3.11", "3.12"],
"2024.10": ["3.9", "3.10", "3.11", "3.12", "3.13"],
"2024.04": ["3.9", "3.10", "3.11", "3.12"],
"2023.12": ["3.9", "3.10", "3.11", "3.12"],
}

LOCAL_REQUIREMENTS_DIR = Path(__file__).parent / "requirements"
Expand Down Expand Up @@ -1147,9 +1147,8 @@ def from_registry(
The image must be built for the `linux/amd64` platform.

If your image does not come with Python installed, you can use the `add_python` parameter
to specify a version of Python to add to the image. Supported versions are `3.8`, `3.9`,
`3.10`, `3.11`, and `3.12`. Otherwise, the image is expected to have Python>3.8 available
on PATH as `python`, along with `pip`.
to specify a version of Python to add to the image. Otherwise, the image is expected to
have Python on PATH as `python`, along with `pip`.

You may also use `setup_dockerfile_commands` to run Dockerfile commands before the
remaining commands run. This might be useful if you want a custom Python installation or to
Expand Down Expand Up @@ -1299,8 +1298,7 @@ def from_dockerfile(
"""Build a Modal image from a local Dockerfile.

If your Dockerfile does not have Python installed, you can use the `add_python` parameter
to specify a version of Python to add to the image. Supported versions are `3.8`, `3.9`,
`3.10`, `3.11`, and `3.12`.
to specify a version of Python to add to the image.

**Example**

Expand Down
1 change: 0 additions & 1 deletion modal/mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
# These can be updated safely, but changes will trigger a rebuild for all images
# that rely on `add_python()` in their constructor.
PYTHON_STANDALONE_VERSIONS: typing.Dict[str, typing.Tuple[str, str]] = {
"3.8": ("20230826", "3.8.17"),
"3.9": ("20230826", "3.9.18"),
"3.10": ("20230826", "3.10.13"),
"3.11": ("20230826", "3.11.5"),
Expand Down
6 changes: 3 additions & 3 deletions modal/requirements/base-images.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"2023.12": "bullseye"
},
"python": {
"2024.10": ["3.8.20", "3.9.20", "3.10.15", "3.11.10", "3.12.6", "3.13.0"],
"2024.04": ["3.8.19", "3.9.19", "3.10.14", "3.11.8", "3.12.2"],
"2023.12": ["3.8.15", "3.9.15", "3.10.8", "3.11.0", "3.12.1"]
"2024.10": ["3.9.20", "3.10.15", "3.11.10", "3.12.6", "3.13.0"],
"2024.04": ["3.9.19", "3.10.14", "3.11.8", "3.12.2"],
"2023.12": ["3.9.15", "3.10.8", "3.11.0", "3.12.1"]
},
"micromamba": {
"2024.10": "1.5.10",
Expand Down
2 changes: 1 addition & 1 deletion modal_version/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
major_number = 0

# Bump this manually on breaking changes, then reset the number in _version_generated.py
minor_number = 65
minor_number = 66

# Right now, automatically increment the patch number in CI
__version__ = f"{major_number}.{minor_number}.{max(build_number, 0)}"
2 changes: 1 addition & 1 deletion modal_version/_version_generated.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright Modal Labs 2024

# Note: Reset this value to -1 whenever you make a minor `0.X` release of the client.
build_number = 66 # git: 875cc88
build_number = -1
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ classifiers =

[options]
packages = find:
python_requires = >=3.8
python_requires = >=3.9
install_requires =
aiohttp
aiostream~=0.5.2
Expand Down
4 changes: 2 additions & 2 deletions test/image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ def get_hash(img: Image) -> str:
spec_file=test_dir / "supports" / "test-conda-environment.yml",
channels=["conda-forge", "my-channel"],
)
assert get_hash(img) == "d9d4c9fe24769ce587877b9752a64486e8f7d8520731110bd2fa666de82f43fd"
assert get_hash(img) == "f8701ce500d6aa1fecefd9c2869aef4a13c77ab03925333c011d7eca60bbf08a"
Copy link
Contributor Author

@mwaskom mwaskom Nov 13, 2024

Choose a reason for hiding this comment

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

This isn't a real change to the Image recipe, but the test-conda-environment.yml support file we use had python_version: 3.8, which I've updated to avoid other issues.


img = base.poetry_install_from_file(
test_dir / "supports" / "test-pyproject.toml",
Expand Down Expand Up @@ -1156,7 +1156,7 @@ def get_hash(img: Image) -> str:
spec_file=test_dir / "supports" / "test-conda-environment.yml",
channels=["conda-forge", "my-channel"],
)
assert get_hash(img) == "769bdbb5aaeb4f6c7eda77e59ee81c6adac9b03ff7e479036b83ec414e8cfec6"
assert get_hash(img) == "072e70b2f05327f606c261ad48a68cf8db5e592e7019f6ee7dbaccf28f2ef537"

img = base.poetry_install_from_file(
test_dir / "supports" / "test-pyproject.toml",
Expand Down
2 changes: 1 addition & 1 deletion test/supports/test-conda-environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ channels:
- pytorch
- defaults
dependencies:
- python=3.8.5
- python=3.12.5
- foo=1.0
- pip:
- bar=2.1
2 changes: 1 addition & 1 deletion test/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ async def write(self, chunk: bytes):


def test_parse_major_minor_version():
assert parse_major_minor_version("3.8") == (3, 8)
assert parse_major_minor_version("3.11") == (3, 11)
assert parse_major_minor_version("3.9.1") == (3, 9)
assert parse_major_minor_version("3.10.1rc0") == (3, 10)
with pytest.raises(ValueError, match="at least an 'X.Y' format"):
Expand Down
Loading