We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Python 3.12 distutils deprecation error
### System Info

```Shell
accelerate 0.26.1, Windows 11, Python 3.12.1
```


### Information

- [ ] The official example scripts
- [x] My own modified scripts

### Tasks

- [ ] One of the scripts in the examples/ folder of Accelerate or an officially supported `no_trainer` script in the `examples` folder of the `transformers` repo (such as `run_no_trainer_glue.py`)
- [X] My own task or dataset (give details below)

### Reproduction

To reproduce behaviour:
1. In Python 3.12 install latest accelerate with
` pip3 install accelerate --upgrade `
2. Try to initialise accelerate with:
```python
from accelerate import Accelerator
accelerator = Accelerator()
```

This results in the error caused by https://github.com/huggingface/accelerate/blob/f88661b5d9f4977b5a1555a92e64ef3cd359cbc9/src/accelerate/utils/environment.py#L19

![image](https://github.com/huggingface/accelerate/assets/7803161/8b88d142-cf67-43b5-9b02-3f9346baa02a)
The fundamental issue is deprecation of distutils as part of https://peps.python.org/pep-0632/

### Expected behavior

Accelerate should not depend on deprecated package and be compatible with Python 3.12+

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/accelerate/utils/environment.py`
Content:
```
1 # Copyright 2022 The HuggingFace Team. All rights reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import os
16 import platform
17 import subprocess
18 import sys
19 from distutils import spawn
20 from typing import Dict
21 
22 import torch
23 
24 
25 def str_to_bool(value) -> int:
26     """
27     Converts a string representation of truth to `True` (1) or `False` (0).
28 
29     True values are `y`, `yes`, `t`, `true`, `on`, and `1`; False value are `n`, `no`, `f`, `false`, `off`, and `0`;
30     """
31     value = value.lower()
32     if value in ("y", "yes", "t", "true", "on", "1"):
33         return 1
34     elif value in ("n", "no", "f", "false", "off", "0"):
35         return 0
36     else:
37         raise ValueError(f"invalid truth value {value}")
38 
39 
40 def get_int_from_env(env_keys, default):
41     """Returns the first positive env value found in the `env_keys` list or the default."""
42     for e in env_keys:
43         val = int(os.environ.get(e, -1))
44         if val >= 0:
45             return val
46     return default
47 
48 
49 def parse_flag_from_env(key, default=False):
50     """Returns truthy value for `key` from the env if available else the default."""
51     value = os.environ.get(key, str(default))
52     return str_to_bool(value) == 1  # As its name indicates `str_to_bool` actually returns an int...
53 
54 
55 def parse_choice_from_env(key, default="no"):
56     value = os.environ.get(key, str(default))
57     return value
58 
59 
60 def are_libraries_initialized(*library_names: str) -> Dict[str, bool]:
61     """
62     Checks if any of `library_names` are imported in the environment. Will return results as a `key:bool` pair.
63     """
64     return [lib_name for lib_name in library_names if lib_name in sys.modules.keys()]
65 
66 
67 def get_gpu_info():
68     """
69     Gets GPU count and names using `nvidia-smi` instead of torch to not initialize CUDA.
70 
71     Largely based on the `gputil` library.
72     """
73     if platform.system() == "Windows":
74         # If platform is Windows and nvidia-smi can't be found in path
75         # try from systemd rive with default installation path
76         command = spawn.find_executable("nvidia-smi")
77         if command is None:
78             command = "%s\\Program Files\\NVIDIA Corporation\\NVSMI\\nvidia-smi.exe" % os.environ["systemdrive"]
79     else:
80         command = "nvidia-smi"
81     # Returns as list of `n` GPUs and their names
82     output = subprocess.check_output(
83         [command, "--query-gpu=count,name", "--format=csv,noheader"], universal_newlines=True
84     )
85     output = output.strip()
86     gpus = output.split(os.linesep)
87     # Get names from output
88     gpu_count = len(gpus)
89     gpu_names = [gpu.split(",")[1].strip() for gpu in gpus]
90     return gpu_names, gpu_count
91 
92 
93 def check_cuda_p2p_ib_support():
94     """
95     Checks if the devices being used have issues with P2P and IB communications, namely any consumer GPU hardware after
96     the 3090.
97 
98     Noteably uses `nvidia-smi` instead of torch to not initialize CUDA.
99     """
100     try:
101         device_names, device_count = get_gpu_info()
102         # As new consumer GPUs get released, add them to `unsupported_devices``
103         unsupported_devices = {"RTX 40"}
104         if device_count > 1:
105             if any(
106                 unsupported_device in device_name
107                 for device_name in device_names
108                 for unsupported_device in unsupported_devices
109             ):
110                 return False
111     except Exception:
112         pass
113     return True
114 
115 
116 def check_fp8_capability():
117     """
118     Checks if all the current GPUs available support FP8.
119 
120     Notably must initialize `torch.cuda` to check.
121     """
122     cuda_device_capacity = torch.cuda.get_device_capability()
123     return cuda_device_capacity >= (8, 9)
124
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/accelerate/utils/environment.py b/src/accelerate/utils/environment.py
--- a/src/accelerate/utils/environment.py
+++ b/src/accelerate/utils/environment.py
@@ -16,7 +16,7 @@
 import platform
 import subprocess
 import sys
-from distutils import spawn
+from shutil import which
 from typing import Dict
 
 import torch
@@ -72,8 +72,8 @@
     """
     if platform.system() == "Windows":
         # If platform is Windows and nvidia-smi can't be found in path
-        # try from systemd rive with default installation path
-        command = spawn.find_executable("nvidia-smi")
+        # try from systemd drive with default installation path
+        command = which("nvidia-smi")
         if command is None:
             command = "%s\\Program Files\\NVIDIA Corporation\\NVSMI\\nvidia-smi.exe" % os.environ["systemdrive"]
     else:

{"golden_diff": "diff --git a/src/accelerate/utils/environment.py b/src/accelerate/utils/environment.py\n--- a/src/accelerate/utils/environment.py\n+++ b/src/accelerate/utils/environment.py\n@@ -16,7 +16,7 @@\n import platform\n import subprocess\n import sys\n-from distutils import spawn\n+from shutil import which\n from typing import Dict\n \n import torch\n@@ -72,8 +72,8 @@\n     \"\"\"\n     if platform.system() == \"Windows\":\n         # If platform is Windows and nvidia-smi can't be found in path\n-        # try from systemd rive with default installation path\n-        command = spawn.find_executable(\"nvidia-smi\")\n+        # try from systemd drive with default installation path\n+        command = which(\"nvidia-smi\")\n         if command is None:\n             command = \"%s\\\\Program Files\\\\NVIDIA Corporation\\\\NVSMI\\\\nvidia-smi.exe\" % os.environ[\"systemdrive\"]\n     else:\n", "issue": "Python 3.12 distutils deprecation error\n### System Info\n\n```Shell\naccelerate 0.26.1, Windows 11, Python 3.12.1\n```\n\n\n### Information\n\n- [ ] The official example scripts\n- [x] My own modified scripts\n\n### Tasks\n\n- [ ] One of the scripts in the examples/ folder of Accelerate or an officially supported `no_trainer` script in the `examples` folder of the `transformers` repo (such as `run_no_trainer_glue.py`)\n- [X] My own task or dataset (give details below)\n\n### Reproduction\n\nTo reproduce behaviour:\r\n1. In Python 3.12 install latest accelerate with\r\n` pip3 install accelerate --upgrade `\r\n2. Try to initialise accelerate with:\r\n```python\r\nfrom accelerate import Accelerator\r\naccelerator = Accelerator()\r\n```\r\n\r\nThis results in the error caused by https://github.com/huggingface/accelerate/blob/f88661b5d9f4977b5a1555a92e64ef3cd359cbc9/src/accelerate/utils/environment.py#L19\r\n\r\n![image](https://github.com/huggingface/accelerate/assets/7803161/8b88d142-cf67-43b5-9b02-3f9346baa02a)\r\nThe fundamental issue is deprecation of distutils as part of https://peps.python.org/pep-0632/\n\n### Expected behavior\n\nAccelerate should not depend on deprecated package and be compatible with Python 3.12+\n", "before_files": [{"content": "# Copyright 2022 The HuggingFace Team. All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport platform\nimport subprocess\nimport sys\nfrom distutils import spawn\nfrom typing import Dict\n\nimport torch\n\n\ndef str_to_bool(value) -> int:\n    \"\"\"\n    Converts a string representation of truth to `True` (1) or `False` (0).\n\n    True values are `y`, `yes`, `t`, `true`, `on`, and `1`; False value are `n`, `no`, `f`, `false`, `off`, and `0`;\n    \"\"\"\n    value = value.lower()\n    if value in (\"y\", \"yes\", \"t\", \"true\", \"on\", \"1\"):\n        return 1\n    elif value in (\"n\", \"no\", \"f\", \"false\", \"off\", \"0\"):\n        return 0\n    else:\n        raise ValueError(f\"invalid truth value {value}\")\n\n\ndef get_int_from_env(env_keys, default):\n    \"\"\"Returns the first positive env value found in the `env_keys` list or the default.\"\"\"\n    for e in env_keys:\n        val = int(os.environ.get(e, -1))\n        if val >= 0:\n            return val\n    return default\n\n\ndef parse_flag_from_env(key, default=False):\n    \"\"\"Returns truthy value for `key` from the env if available else the default.\"\"\"\n    value = os.environ.get(key, str(default))\n    return str_to_bool(value) == 1  # As its name indicates `str_to_bool` actually returns an int...\n\n\ndef parse_choice_from_env(key, default=\"no\"):\n    value = os.environ.get(key, str(default))\n    return value\n\n\ndef are_libraries_initialized(*library_names: str) -> Dict[str, bool]:\n    \"\"\"\n    Checks if any of `library_names` are imported in the environment. Will return results as a `key:bool` pair.\n    \"\"\"\n    return [lib_name for lib_name in library_names if lib_name in sys.modules.keys()]\n\n\ndef get_gpu_info():\n    \"\"\"\n    Gets GPU count and names using `nvidia-smi` instead of torch to not initialize CUDA.\n\n    Largely based on the `gputil` library.\n    \"\"\"\n    if platform.system() == \"Windows\":\n        # If platform is Windows and nvidia-smi can't be found in path\n        # try from systemd rive with default installation path\n        command = spawn.find_executable(\"nvidia-smi\")\n        if command is None:\n            command = \"%s\\\\Program Files\\\\NVIDIA Corporation\\\\NVSMI\\\\nvidia-smi.exe\" % os.environ[\"systemdrive\"]\n    else:\n        command = \"nvidia-smi\"\n    # Returns as list of `n` GPUs and their names\n    output = subprocess.check_output(\n        [command, \"--query-gpu=count,name\", \"--format=csv,noheader\"], universal_newlines=True\n    )\n    output = output.strip()\n    gpus = output.split(os.linesep)\n    # Get names from output\n    gpu_count = len(gpus)\n    gpu_names = [gpu.split(\",\")[1].strip() for gpu in gpus]\n    return gpu_names, gpu_count\n\n\ndef check_cuda_p2p_ib_support():\n    \"\"\"\n    Checks if the devices being used have issues with P2P and IB communications, namely any consumer GPU hardware after\n    the 3090.\n\n    Noteably uses `nvidia-smi` instead of torch to not initialize CUDA.\n    \"\"\"\n    try:\n        device_names, device_count = get_gpu_info()\n        # As new consumer GPUs get released, add them to `unsupported_devices``\n        unsupported_devices = {\"RTX 40\"}\n        if device_count > 1:\n            if any(\n                unsupported_device in device_name\n                for device_name in device_names\n                for unsupported_device in unsupported_devices\n            ):\n                return False\n    except Exception:\n        pass\n    return True\n\n\ndef check_fp8_capability():\n    \"\"\"\n    Checks if all the current GPUs available support FP8.\n\n    Notably must initialize `torch.cuda` to check.\n    \"\"\"\n    cuda_device_capacity = torch.cuda.get_device_capability()\n    return cuda_device_capacity >= (8, 9)\n", "path": "src/accelerate/utils/environment.py"}], "after_files": [{"content": "# Copyright 2022 The HuggingFace Team. All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport platform\nimport subprocess\nimport sys\nfrom shutil import which\nfrom typing import Dict\n\nimport torch\n\n\ndef str_to_bool(value) -> int:\n    \"\"\"\n    Converts a string representation of truth to `True` (1) or `False` (0).\n\n    True values are `y`, `yes`, `t`, `true`, `on`, and `1`; False value are `n`, `no`, `f`, `false`, `off`, and `0`;\n    \"\"\"\n    value = value.lower()\n    if value in (\"y\", \"yes\", \"t\", \"true\", \"on\", \"1\"):\n        return 1\n    elif value in (\"n\", \"no\", \"f\", \"false\", \"off\", \"0\"):\n        return 0\n    else:\n        raise ValueError(f\"invalid truth value {value}\")\n\n\ndef get_int_from_env(env_keys, default):\n    \"\"\"Returns the first positive env value found in the `env_keys` list or the default.\"\"\"\n    for e in env_keys:\n        val = int(os.environ.get(e, -1))\n        if val >= 0:\n            return val\n    return default\n\n\ndef parse_flag_from_env(key, default=False):\n    \"\"\"Returns truthy value for `key` from the env if available else the default.\"\"\"\n    value = os.environ.get(key, str(default))\n    return str_to_bool(value) == 1  # As its name indicates `str_to_bool` actually returns an int...\n\n\ndef parse_choice_from_env(key, default=\"no\"):\n    value = os.environ.get(key, str(default))\n    return value\n\n\ndef are_libraries_initialized(*library_names: str) -> Dict[str, bool]:\n    \"\"\"\n    Checks if any of `library_names` are imported in the environment. Will return results as a `key:bool` pair.\n    \"\"\"\n    return [lib_name for lib_name in library_names if lib_name in sys.modules.keys()]\n\n\ndef get_gpu_info():\n    \"\"\"\n    Gets GPU count and names using `nvidia-smi` instead of torch to not initialize CUDA.\n\n    Largely based on the `gputil` library.\n    \"\"\"\n    if platform.system() == \"Windows\":\n        # If platform is Windows and nvidia-smi can't be found in path\n        # try from systemd drive with default installation path\n        command = which(\"nvidia-smi\")\n        if command is None:\n            command = \"%s\\\\Program Files\\\\NVIDIA Corporation\\\\NVSMI\\\\nvidia-smi.exe\" % os.environ[\"systemdrive\"]\n    else:\n        command = \"nvidia-smi\"\n    # Returns as list of `n` GPUs and their names\n    output = subprocess.check_output(\n        [command, \"--query-gpu=count,name\", \"--format=csv,noheader\"], universal_newlines=True\n    )\n    output = output.strip()\n    gpus = output.split(os.linesep)\n    # Get names from output\n    gpu_count = len(gpus)\n    gpu_names = [gpu.split(\",\")[1].strip() for gpu in gpus]\n    return gpu_names, gpu_count\n\n\ndef check_cuda_p2p_ib_support():\n    \"\"\"\n    Checks if the devices being used have issues with P2P and IB communications, namely any consumer GPU hardware after\n    the 3090.\n\n    Noteably uses `nvidia-smi` instead of torch to not initialize CUDA.\n    \"\"\"\n    try:\n        device_names, device_count = get_gpu_info()\n        # As new consumer GPUs get released, add them to `unsupported_devices``\n        unsupported_devices = {\"RTX 40\"}\n        if device_count > 1:\n            if any(\n                unsupported_device in device_name\n                for device_name in device_names\n                for unsupported_device in unsupported_devices\n            ):\n                return False\n    except Exception:\n        pass\n    return True\n\n\ndef check_fp8_capability():\n    \"\"\"\n    Checks if all the current GPUs available support FP8.\n\n    Notably must initialize `torch.cuda` to check.\n    \"\"\"\n    cuda_device_capacity = torch.cuda.get_device_capability()\n    return cuda_device_capacity >= (8, 9)\n", "path": "src/accelerate/utils/environment.py"}]}