Skip to content

Commit

Permalink
chore: remove support for Python 3.7; prefer 3.8 (#7329)
Browse files Browse the repository at this point in the history
Python 3.7 is EOL.

* Some docs that referred to 3.7 now refer to 3.8
* Training API "how to" doc no longer mentions any 3.7 docker images
* `CONTRIBUTING.md` no longer says to upgrade pip when installing determined
* `CONTRIBUTING.md` has revised text about Python requirements
* mypy tests against 3.8.
* Features new to 3.8 can be used without suppressing type checking or conditional imports. These changes have been made.
* No longer run `test-cli` in CircleCI against Python 3.7.
* There are no wheels for TF1 using Python 3.8. Removing 3.7 support means TF1 cannot be used. In previous commits, we removed support of TF1. We also clean up those references here. In particular:
  - `e2e_tests/tests/command/test_run:test_k8_init_containers` and  `e2e_tests/tests/command/test_run:test_k8_sidecars` now run on TF2 images
  - Removed references to TF1 images in `e2e_tests`.
  - Removed references to TF1 Docker images in `bumpenvs.yaml`
  • Loading branch information
wes-turner authored Mar 4, 2024
1 parent c404c8e commit fa856ab
Show file tree
Hide file tree
Showing 15 changed files with 27 additions and 82 deletions.
5 changes: 1 addition & 4 deletions .circleci/real_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ orbs:
win: circleci/windows@5.0.0

executors:
python-37:
docker:
- image: python:3.7-slim-buster
python-38:
docker:
- image: python:3.8-slim-buster
Expand Down Expand Up @@ -2746,7 +2743,7 @@ workflows:
matrix:
parameters:
executor-name:
["python-37", "python-38", "python-39", "win/default"]
["python-38", "python-39", "win/default"]

test-unit:
jobs:
Expand Down
6 changes: 2 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,8 @@ git clone --recurse-submodules https://github.com/determined-ai/determined.git

#### Prerequisites

- Go (>= 1.20)
- Python (>= 3.7.4, <= 3.9), including:
- python3-venv
- Go (>= 1.22)
- Python 3.8. Newer Python versions are partially supported, but some components may not work (e.g., docs build).
- python3-wheel
- python3-dev
- Node (>= 20.9.0, < 21)
Expand Down Expand Up @@ -118,7 +117,6 @@ source $HOME/.profile
cd determined
python3 -m venv $HOME/.virtualenvs/determined
. $HOME/.virtualenvs/determined/bin/activate
$HOME/.virtualenvs/determined/bin/python3.9 -m pip install --upgrade pip
export PATH=$PATH:$HOME/go/bin
make all
```
Expand Down
1 change: 0 additions & 1 deletion docs/model-dev-guide/api-guides/apis-howto/_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ respectively:
We also provide lightweight CPU-only counterparts:

- ``determinedai/environments:py-3.9-pytorch-1.12-tf-2.11-cpu-0.27.1``
- ``determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-0.21.2``
- ``determinedai/environments:py-3.8-tf-2.8-cpu-0.27.1``

To change the container image used for an experiment, specify :ref:`environment.image
Expand Down
7 changes: 4 additions & 3 deletions docs/tools/cli/cli-ug.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ and upgrade.
Installation
**************

The CLI is distributed as a Python wheel package and requires Python >= 3.7. We recommend setting up
a `virtualenv <https://virtualenv.pypa.io/en/latest/>`__ and using the ``pip`` utility to install
``determined`` into the environment:
The command-line interface (CLI) is distributed in the form of a Python wheel package and requires
Python version 3.8 or later. We recommend setting up a `virtualenv
<https://virtualenv.pypa.io/en/latest/>`__ and using the ``pip`` utility to install ``determined``
into the environment:

.. code::
Expand Down
2 changes: 1 addition & 1 deletion e2e_tests/mypy.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[mypy]
mypy_path = ../harness
python_version = 3.7
python_version = 3.8
follow_imports = silent
ignore_missing_imports = True

Expand Down
4 changes: 2 additions & 2 deletions e2e_tests/tests/command/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def test_k8s_init_containers() -> None:
"spec": {
"initContainers": [
{
"image": conf.TF1_CPU_IMAGE,
"image": conf.TF2_CPU_IMAGE,
"name": "simple-init-container",
"command": ["/bin/bash"],
"args": ["-c", "exit 1"],
Expand All @@ -313,7 +313,7 @@ def test_k8s_sidecars() -> None:
"spec": {
"containers": [
{
"image": conf.TF1_CPU_IMAGE,
"image": conf.TF2_CPU_IMAGE,
"name": "sidecar",
"command": ["/bin/bash"],
}
Expand Down
8 changes: 0 additions & 8 deletions e2e_tests/tests/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,14 @@
MAX_TRIAL_BUILD_SECS = 90


DEFAULT_TF1_CPU_IMAGE = "determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-6eceaca"
DEFAULT_TF2_CPU_IMAGE = "determinedai/environments:py-3.9-pytorch-1.12-tf-2.11-cpu-f66cbce"
DEFAULT_TF1_GPU_IMAGE = "determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-6eceaca"
DEFAULT_TF2_GPU_IMAGE = "determinedai/environments:cuda-11.3-pytorch-1.12-tf-2.11-gpu-f66cbce"
DEFAULT_PT_CPU_IMAGE = "determinedai/environments:py-3.9-pytorch-1.12-cpu-f66cbce"
DEFAULT_PT_GPU_IMAGE = "determinedai/environments:cuda-11.3-pytorch-1.12-gpu-f66cbce"
DEFAULT_PT2_CPU_IMAGE = "determinedai/environments:py-3.10-pytorch-2.0-cpu-f66cbce"
DEFAULT_PT2_GPU_IMAGE = "determinedai/environments:cuda-11.8-pytorch-2.0-gpu-f66cbce"

TF1_CPU_IMAGE = os.environ.get("TF1_CPU_IMAGE") or DEFAULT_TF1_CPU_IMAGE
TF2_CPU_IMAGE = os.environ.get("TF2_CPU_IMAGE") or DEFAULT_TF2_CPU_IMAGE
TF1_GPU_IMAGE = os.environ.get("TF1_GPU_IMAGE") or DEFAULT_TF1_GPU_IMAGE
TF2_GPU_IMAGE = os.environ.get("TF2_GPU_IMAGE") or DEFAULT_TF2_GPU_IMAGE
PT_CPU_IMAGE = os.environ.get("PT_CPU_IMAGE") or DEFAULT_PT_CPU_IMAGE
PT_GPU_IMAGE = os.environ.get("PT_GPU_IMAGE") or DEFAULT_PT_GPU_IMAGE
Expand Down Expand Up @@ -143,10 +139,6 @@ def set_image(config: Dict[Any, Any], cpu_image: str, gpu_image: str) -> Dict[An
return config


def set_tf1_image(config: Dict[Any, Any]) -> Dict[Any, Any]:
return set_image(config, TF1_CPU_IMAGE, TF1_GPU_IMAGE)


def set_tf2_image(config: Dict[Any, Any]) -> Dict[Any, Any]:
return set_image(config, TF2_CPU_IMAGE, TF2_GPU_IMAGE)

Expand Down
2 changes: 1 addition & 1 deletion e2e_tests/tests/model_hub/test_mmdetection.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def set_docker_image(config: Dict) -> Dict:
)

config = conf.set_image(
config, conf.TF1_CPU_IMAGE, f"determinedai/model-hub-mmdetection:{git_short_hash}"
config, conf.TF2_CPU_IMAGE, f"determinedai/model-hub-mmdetection:{git_short_hash}"
)
return config

Expand Down
34 changes: 10 additions & 24 deletions harness/determined/cli/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import shutil
import subprocess
import sys
import typing
from argparse import Namespace
from collections.abc import Sequence
from typing import Any, Dict, List, OrderedDict, Tuple
from typing import Any, Dict, List, Optional, OrderedDict, Tuple, Union, get_args, get_origin
from urllib import parse

from termcolor import colored
Expand Down Expand Up @@ -53,10 +54,7 @@ def curl(args: Namespace) -> None:
cmd += args.curl_args

if args.x:
if hasattr(shlex, "join"): # added in py 3.8
print(shlex.join(cmd)) # type: ignore
else:
print(" ".join(shlex.quote(arg) for arg in cmd))
print(shlex.join(cmd))

if not sys.stdout.isatty():
output = subprocess.run(cmd)
Expand Down Expand Up @@ -99,20 +97,13 @@ def unwrap_optional(annotation: Any) -> Any:
"""
evaluates and unwraps a typing.Optional annotation to its inner type.
"""
import typing

try:
from typing import get_args, get_origin # type: ignore
except ImportError:
raise errors.CliError("python >= 3.8 is required to use this feature")

local_context = {
"typing": typing,
"Optional": typing.Optional,
"Union": typing.Union,
"List": typing.List,
"Sequence": typing.Sequence,
"Dict": typing.Dict,
"Optional": Optional,
"Union": Union,
"List": List,
"Sequence": Sequence,
"Dict": Dict,
"NoneType": type(None),
}
if isinstance(annotation, str):
Expand All @@ -123,10 +114,10 @@ def unwrap_optional(annotation: Any) -> Any:
origin = get_origin(annotation)
args = get_args(annotation)

if origin is typing.Union:
if origin is Union:
if len(args) == 2 and type(None) in args:
return args[0]
elif origin is typing.Optional:
elif origin is Optional:
return args[0]
return annotation

Expand All @@ -136,11 +127,6 @@ def is_supported_annotation(annot: Any) -> bool:
determines if a our CLI deserializer supports a given type annotation
and subsequently a binding's parameter.
"""
try:
from typing import get_args, get_origin # type: ignore
except ImportError:
raise errors.CliError("python >= 3.8 is required to use this feature")

annot = unwrap_optional(annot)
supported_types = [str, int, float, type(None), bool]
if annot in supported_types:
Expand Down
16 changes: 2 additions & 14 deletions harness/determined/common/experimental/checkpoint/_checkpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import logging
import pathlib
import shutil
import sys
import tarfile
import warnings
from typing import Any, Dict, Iterable, List, Optional
Expand Down Expand Up @@ -276,23 +275,12 @@ def _download_auto(
"but they both failed."
) from e

def _shutil_copytree(self, src: str, dst: str) -> None:
# TODO: remove version check once we drop support for Python 3.7
if sys.version_info.minor >= 8:
shutil.copytree(
src,
dst,
dirs_exist_ok=True,
) # type: ignore
else:
shutil.copytree(src, dst)

def _download_direct(
self, checkpoint_storage: Dict[str, Any], local_ckpt_dir: pathlib.Path
) -> None:
if checkpoint_storage["type"] == "shared_fs":
src_ckpt_dir = self._find_shared_fs_path(checkpoint_storage)
self._shutil_copytree(str(src_ckpt_dir), str(local_ckpt_dir))
shutil.copytree(str(src_ckpt_dir), str(local_ckpt_dir), dirs_exist_ok=True)
elif checkpoint_storage["type"] == "directory":
src_ckpt_dir = pathlib.Path(checkpoint_storage["container_path"], self.uuid)
if not src_ckpt_dir.exists():
Expand All @@ -301,7 +289,7 @@ def _download_direct(
"the same checkpoint storage directory present on the local machine as the "
"task runtime storage configuration.".format(self.uuid, src_ckpt_dir)
)
self._shutil_copytree(str(src_ckpt_dir), str(local_ckpt_dir))
shutil.copytree(str(src_ckpt_dir), str(local_ckpt_dir), dirs_exist_ok=True)
else:
local_ckpt_dir.mkdir(parents=True, exist_ok=True)
manager = storage.build(
Expand Down
2 changes: 1 addition & 1 deletion harness/mypy.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[mypy]
python_version = 3.7
python_version = 3.8
follow_imports = silent
ignore_missing_imports = True

Expand Down
2 changes: 1 addition & 1 deletion model_hub/mypy.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[mypy]
mypy_path = ../harness
python_version = 3.7
python_version = 3.8
follow_imports = silent
ignore_missing_imports = True

Expand Down
2 changes: 1 addition & 1 deletion schemas/mypy.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[mypy]
python_version = 3.7
python_version = 3.8
follow_imports = silent
ignore_missing_imports = True

Expand Down
2 changes: 1 addition & 1 deletion tools/mypy.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[mypy]
python_version = 3.7
python_version = 3.8
follow_imports = silent
ignore_missing_imports = True

Expand Down
16 changes: 0 additions & 16 deletions tools/scripts/bumpenvs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,6 @@ pytorch20_tf210_rocm56_0_hashed: {new: determinedai/environments:rocm-5.6-pytorc
pytorch20_tf210_rocm56_0_versioned: {new: determinedai/environments:rocm-5.6-pytorch-2.0-tf-2.10-rocm-ompi-0.27.1}
pytorch20_tf210_rocm56_1_hashed: {new: determinedai/environments:rocm-5.6-pytorch-2.0-tf-2.10-rocm-ompi-f66cbce}
pytorch20_tf210_rocm56_1_versioned: {new: determinedai/environments:rocm-5.6-pytorch-2.0-tf-2.10-rocm-ompi-0.27.1}
tf1_cpu_0_hashed: {new: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-6eceaca,
old: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-a8b9c02}
tf1_cpu_0_versioned: {new: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-0.21.2,
old: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-0.21.1}
tf1_cpu_1_hashed: {new: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-mpi-6eceaca,
old: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-mpi-a8b9c02}
tf1_cpu_1_versioned: {new: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-mpi-0.21.2,
old: determinedai/environments:py-3.7-pytorch-1.7-tf-1.15-cpu-mpi-0.21.1}
tf1_gpu_0_hashed: {new: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-6eceaca,
old: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-a8b9c02}
tf1_gpu_0_versioned: {new: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-0.21.2,
old: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-0.21.1}
tf1_gpu_1_hashed: {new: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-mpi-6eceaca,
old: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-mpi-a8b9c02}
tf1_gpu_1_versioned: {new: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-mpi-0.21.2,
old: determinedai/environments:cuda-10.2-pytorch-1.7-tf-1.15-gpu-mpi-0.21.1}
tf24_cpu_0_hashed: {new: determinedai/environments:py-3.8-pytorch-1.9-tf-2.4-cpu-24586f0,
old: determinedai/environments-dev:py-3.8-pytorch-1.9-tf-2.4-cpu-1c769fb}
tf24_cpu_0_versioned: {new: determinedai/environments:py-3.8-pytorch-1.9-tf-2.4-cpu-0.19.10,
Expand Down

0 comments on commit fa856ab

Please sign in to comment.