Skip to content

Commit 1f60f13

Browse files
authored
Check Environment Script (#9038)
Fixes # . ### Description This adds a script to check the environment for installed libraries, if PyTorch works, if MONAI works, and print platform information. This script is meant to be useable without anything being installed other than Python itself, so it can be used to inspect an environment before attempting to install MONAI or produce diagnostic information when some environmental failure occurs. The script can be run remotely with `curl` as it only relies on the standard library. Minor tweaks are made to the CI action to use this script rather than the copy-pasted short Python lines. ### Types of changes <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [x] Non-breaking change (fix or new feature that would not break existing functionality). - [ ] Breaking change (fix or new feature that would cause existing functionality to change). - [x] New tests added to cover the changes. - [ ] Integration tests passed locally by running `./runtests.sh -f -u --net --coverage`. - [ ] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. - [ ] In-line docstrings updated. - [ ] Documentation updated, tested `make html` command in the `docs/` folder. --------- Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
1 parent d1306f6 commit 1f60f13

8 files changed

Lines changed: 294 additions & 54 deletions

File tree

.github/workflows/cicd_tests.yml

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,10 @@ jobs:
146146
python -m pip install --no-build-isolation .[testing]
147147
python -m pip list
148148
shell: bash
149-
- if: matrix.os == 'linux-gpu-runner'
150-
name: Print GPU Info
151-
run: |
152-
nvidia-smi
153-
python -c 'import torch; print(torch.rand(2,2).to("cuda:0"))'
154-
shell: bash
155149
- name: Run quick tests
156150
run: |
157-
python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
158-
python -c "import monai; monai.config.print_config()"
151+
nvidia-smi || true
152+
python monai/config/check_env.py --env --monai
159153
./runtests.sh --min
160154
shell: bash
161155
env:
@@ -225,22 +219,19 @@ jobs:
225219
- name: Run compiled (${{ runner.os }})
226220
run: |
227221
python -m pip uninstall -y monai
228-
BUILD_MONAI=1 python -m pip install --no-build-isolation -e . # compile the cpp extensions in-place with -e
229-
# ensure extensions were compiled
222+
BUILD_MONAI=1 python -m pip install --no-build-isolation -e . # compile the cpp extensions
230223
python -c 'import monai._C' > /dev/null
224+
nvidia-smi || true
225+
python monai/config/check_env.py --env --monai
231226
shell: bash
232227
- if: runner.os != 'macOS'
233228
name: Run full tests
234229
run: |
235-
python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
236-
python -c "import monai; monai.config.print_config()"
237230
python -m unittest -v
238231
shell: bash
239232
- if: runner.os == 'macOS'
240233
name: Run min tests
241234
run: |
242-
python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
243-
python -c "import monai; monai.config.print_config()"
244235
# TODO: enable large range of macOS tests which don't take a very long time
245236
./runtests.sh --min
246237
shell: bash
@@ -351,8 +342,7 @@ jobs:
351342
run: |
352343
# install from wheel
353344
python -m pip install --no-build-isolation monai*.whl --extra-index-url $INDEX_URL
354-
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
355-
python -c 'import monai; print(monai.__file__)'
345+
python -m monai.config
356346
python -m pip uninstall -y monai
357347
rm monai*.whl
358348
- name: Install source archive
@@ -361,13 +351,11 @@ jobs:
361351
for name in *.tar.gz; do break; done
362352
echo $name
363353
python -m pip install --no-build-isolation ${name}[all] --extra-index-url $INDEX_URL
364-
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
365-
python -c 'import monai; print(monai.__file__)'
354+
python -m monai.config
366355
python -m pip uninstall -y monai
367356
- name: Install using uv
368357
working-directory: ${{ steps.root.outputs.pwd }}
369358
run: |
370359
pip install uv
371360
uv pip install --system --no-build-isolation .[all] --extra-index-url $INDEX_URL
372-
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
373-
python -c 'import monai; print(monai.__file__)'
361+
python -m monai.config

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
include versioneer.py
22
include monai/_version.py
3+
include monai/config/check_env.py
34

45
include README.md
56
include LICENSE

monai/config/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from .deviceconfig import (
1515
USE_COMPILED,
1616
USE_META_DICT,
17-
IgniteInfo,
1817
get_config_values,
1918
get_gpu_info,
2019
get_optional_config_values,

monai/config/__main__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) MONAI Consortium
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
11+
12+
if __name__ == "__main__":
13+
import monai
14+
15+
monai.config.print_debug_info() # type: ignore

monai/config/check_env.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#! /usr/bin/env python
2+
3+
# Copyright (c) MONAI Consortium
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
"""
15+
Script for checking various elements of the runtime environment and printing a large amount of diagnostic information.
16+
17+
This is meant to be used for debugging environments used with MONAI, but doesn't directly need MONAI itself. It will
18+
print information about the environment, including trying to get installed packages, test PyTorch with CUDA, and then
19+
have MONAI print its debugging information if no errors encountered. If MONAI is not installed this script should still
20+
work and produce useful information. Only standard libraries are needed in case a bare environment is being used.
21+
22+
This can be run as a program with the following options to see all outputs:
23+
24+
python check_env.py --env --monai
25+
26+
With no options at all this can be used to test that PyTorch is installed and can move a tensor to a device. This is
27+
useful when creating a fresh test environment and MONAI isn't present yet but it's good practice to valid PyTorch.
28+
Environment variables can be printed by using `--envars` with `--env`, however the output from this is not checked for
29+
secrets so users
30+
31+
This can also be used remotely with only Python installed to get current environment diagnostic info:
32+
33+
curl https://raw.githubusercontent.com/Project-MONAI/MONAI/refs/heads/dev/monai/config/check_env.py | python
34+
"""
35+
36+
from __future__ import annotations
37+
38+
import argparse
39+
import getpass
40+
import multiprocessing
41+
import os
42+
import platform
43+
import shutil
44+
import subprocess
45+
import sys
46+
from functools import partial
47+
48+
DESC = """
49+
Script for checking various elements of the runtime environment and printing a large amount of diagnostic information.
50+
This is used for debugging your environment by printing out various system statistics and diagnostic information. It
51+
checks PyTorch and MONAI are installed and functioning. A typical use case is with the `--env` and `--monai` options.
52+
"""
53+
54+
USER = getpass.getuser()
55+
HOST = platform.node()
56+
efprint = partial(print, flush=True, file=sys.stderr)
57+
58+
59+
def fprint(*args, **kwargs):
60+
"""
61+
Print with flushing, replacing the username and hostname values with placeholders for better anonymization.
62+
"""
63+
kwargs["flush"] = True
64+
content = " ".join(map(str, args))
65+
content = content.replace(USER, "<user>").replace(HOST, "<host>")
66+
print(content, **kwargs)
67+
68+
69+
def print_platform():
70+
"""
71+
Print basic platform information.
72+
"""
73+
fprint(platform.platform())
74+
fprint("uname:", list(platform.uname()))
75+
fprint("CPU:", platform.processor(), "Count:", multiprocessing.cpu_count())
76+
fprint("Python:", sys.executable, platform.python_implementation(), platform.python_version())
77+
78+
79+
def print_environment_vars():
80+
"""
81+
Print all environment variables other than a few known pointless ones.
82+
"""
83+
fprint("Environment:")
84+
for k, v in os.environ.items():
85+
if k not in ("LS_COLORS", "PS1", "PS2"):
86+
fprint(f" {k}:", v)
87+
88+
89+
def print_environment():
90+
"""
91+
Print the installed environment using `conda` or `pip`, fail if neither are present.
92+
"""
93+
try:
94+
cmd = ("conda", "env", "export") if shutil.which("conda") else ("pip", "list")
95+
96+
result = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
97+
fprint(result.decode())
98+
return True
99+
except Exception as e:
100+
efprint(f"Exception encountered getting environment with conda/pip: {e}")
101+
return False
102+
103+
104+
def check_torch():
105+
"""
106+
Check PyTorch is installed and a tensor can be created.
107+
"""
108+
try:
109+
import torch
110+
111+
t = torch.rand(2, 3) * 5
112+
fprint("PyTorch:", torch.__version__, torch.__path__)
113+
fprint("Test tensor:", t.flatten())
114+
return True
115+
except ImportError:
116+
efprint("PyTorch not installed")
117+
return False
118+
119+
120+
def check_torch_cuda():
121+
"""
122+
Check CUDA capability in PyTorch by moving a tensor to each available device.
123+
"""
124+
import torch
125+
126+
fprint("CUDA version:", torch.version.cuda)
127+
128+
try:
129+
dcount = torch.cuda.device_count()
130+
fprint("PyTorch GPU Count:", dcount)
131+
132+
for d in range(dcount):
133+
fprint(f" {torch.cuda.get_device_properties(d)}")
134+
t = torch.rand(2, 3).to(torch.device(f"cuda:{d}")) * 5
135+
fprint("Test tensor:", t.flatten())
136+
return True
137+
except Exception as e:
138+
efprint(f"PyTorch encountered exception creating GPU tensor on device {d}: {e}")
139+
return False
140+
141+
142+
def check_monai():
143+
"""
144+
Check MONAI by importing it then printing its debug info.
145+
"""
146+
try:
147+
import monai
148+
149+
monai.config.print_debug_info() # type: ignore
150+
return True
151+
except ImportError:
152+
efprint("MONAI not installed")
153+
return False
154+
155+
156+
if __name__ == "__main__":
157+
parser = argparse.ArgumentParser(prog="check_env.py", description=DESC.strip())
158+
parser.add_argument("--env", default=False, action="store_true", help="Print environment info")
159+
parser.add_argument("--envvars", default=False, action="store_true", help="Include environment variables")
160+
parser.add_argument("--monai", default=False, action="store_true", help="Print MONAI info")
161+
args = parser.parse_args()
162+
163+
fprint("=" * 10, "Platform Info", "=" * 10)
164+
print_platform()
165+
166+
if args.env:
167+
fprint("=" * 10, "Checking Environment", "=" * 10)
168+
if args.envvars:
169+
print_environment_vars()
170+
print_environment()
171+
172+
fprint("=" * 10, "Checking PyTorch", "=" * 10)
173+
174+
if not check_torch():
175+
efprint("Exiting early, no valid PyTorch install found.")
176+
sys.exit(1)
177+
178+
if not check_torch_cuda():
179+
efprint("Exiting early, PyTorch encountered CUDA error.")
180+
sys.exit(1)
181+
182+
if args.monai:
183+
fprint("=" * 10, "Checking MONAI", "=" * 10)
184+
check_monai()

0 commit comments

Comments
 (0)