We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ENH: Add support for RFC 87: Signed int8 data type for raster
        Cf https://github.com/OSGeo/gdal/pull/6634 "RFC 87: Signed int8 data type for raster" that will likely be implemented in GDAL 3.7

_Originally posted by @rouault in https://github.com/rasterio/rasterio/issues/1595#issuecomment-1307086052_
      

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rasterio/dtypes.py`
Content:
```
1 """Mapping of GDAL to Numpy data types.
2 
3 Since 0.13 we are not importing numpy here and data types are strings.
4 Happily strings can be used throughout Numpy and so existing code will
5 not break.
6 
7 """
8 import numpy
9 
10 from rasterio.env import GDALVersion
11 
12 _GDAL_AT_LEAST_35 = GDALVersion.runtime().at_least("3.5")
13 
14 bool_ = 'bool'
15 ubyte = uint8 = 'uint8'
16 sbyte = int8 = 'int8'
17 uint16 = 'uint16'
18 int16 = 'int16'
19 uint32 = 'uint32'
20 int32 = 'int32'
21 uint64 = 'uint64'
22 int64 = 'int64'
23 float32 = 'float32'
24 float64 = 'float64'
25 complex_ = 'complex'
26 complex64 = 'complex64'
27 complex128 = 'complex128'
28 
29 complex_int16 = "complex_int16"
30 
31 dtype_fwd = {
32     0: None,  # GDT_Unknown
33     1: ubyte,  # GDT_Byte
34     2: uint16,  # GDT_UInt16
35     3: int16,  # GDT_Int16
36     4: uint32,  # GDT_UInt32
37     5: int32,  # GDT_Int32
38     6: float32,  # GDT_Float32
39     7: float64,  # GDT_Float64
40     8: complex_int16,  # GDT_CInt16
41     9: complex64,  # GDT_CInt32
42     10: complex64,  # GDT_CFloat32
43     11: complex128,  # GDT_CFloat64
44 }
45 
46 if _GDAL_AT_LEAST_35:
47     dtype_fwd[12] = int64 # GDT_Int64
48     dtype_fwd[13] = uint64 # GDT_UInt64
49 
50 dtype_rev = dict((v, k) for k, v in dtype_fwd.items())
51 
52 dtype_rev["uint8"] = 1
53 dtype_rev["int8"] = 1
54 dtype_rev["complex"] = 11
55 dtype_rev["complex_int16"] = 8
56 
57 
58 def _get_gdal_dtype(type_name):
59     try:
60         return dtype_rev[type_name]
61     except KeyError:
62         raise TypeError(
63             f"Unsupported data type {type_name}. "
64             f"Allowed data types: {list(dtype_rev)}."
65         )
66 
67 typename_fwd = {
68     0: 'Unknown',
69     1: 'Byte',
70     2: 'UInt16',
71     3: 'Int16',
72     4: 'UInt32',
73     5: 'Int32',
74     6: 'Float32',
75     7: 'Float64',
76     8: 'CInt16',
77     9: 'CInt32',
78     10: 'CFloat32',
79     11: 'CFloat64'}
80 
81 if _GDAL_AT_LEAST_35:
82     typename_fwd[12] = 'Int64'
83     typename_fwd[13] = 'UInt64'
84 
85 typename_rev = dict((v, k) for k, v in typename_fwd.items())
86 
87 dtype_ranges = {
88     'int8': (-128, 127),
89     'uint8': (0, 255),
90     'uint16': (0, 65535),
91     'int16': (-32768, 32767),
92     'uint32': (0, 4294967295),
93     'int32': (-2147483648, 2147483647),
94     'float32': (-3.4028235e+38, 3.4028235e+38),
95     'float64': (-1.7976931348623157e+308, 1.7976931348623157e+308)}
96 
97 if _GDAL_AT_LEAST_35:
98     dtype_ranges['int64'] = (-9223372036854775808, 9223372036854775807)
99     dtype_ranges['uint64'] = (0, 18446744073709551615)
100 
101 
102 def in_dtype_range(value, dtype):
103     """
104     Check if the value is within the dtype range
105     """
106     if numpy.dtype(dtype).kind == "f" and (numpy.isinf(value) or numpy.isnan(value)):
107         return True
108     range_min, range_max = dtype_ranges[dtype]
109     return range_min <= value <= range_max
110 
111 
112 def _gdal_typename(dt):
113     try:
114         return typename_fwd[dtype_rev[dt]]
115     except KeyError:
116         return typename_fwd[dtype_rev[dt().dtype.name]]
117 
118 
119 def check_dtype(dt):
120     """Check if dtype is a known dtype."""
121     if str(dt) in dtype_rev:
122         return True
123     elif callable(dt) and str(dt().dtype) in dtype_rev:
124         return True
125     return False
126 
127 
128 def get_minimum_dtype(values):
129     """Determine minimum type to represent values.
130 
131     Uses range checking to determine the minimum integer or floating point
132     data type required to represent values.
133 
134     Parameters
135     ----------
136     values: list-like
137 
138 
139     Returns
140     -------
141     rasterio dtype string
142     """
143     import numpy as np
144 
145     if not is_ndarray(values):
146         values = np.array(values)
147 
148     min_value = values.min()
149     max_value = values.max()
150 
151     if values.dtype.kind in ('i', 'u'):
152         if min_value >= 0:
153             if max_value <= 255:
154                 return uint8
155             elif max_value <= 65535:
156                 return uint16
157             elif max_value <= 4294967295:
158                 return uint32
159             if not _GDAL_AT_LEAST_35:
160                 raise ValueError("Values out of range for supported dtypes")
161             return uint64
162         elif min_value >= -32768 and max_value <= 32767:
163             return int16
164         elif min_value >= -2147483648 and max_value <= 2147483647:
165             return int32
166         if not _GDAL_AT_LEAST_35:
167             raise ValueError("Values out of range for supported dtypes")
168         return int64
169 
170     else:
171         if min_value >= -3.4028235e+38 and max_value <= 3.4028235e+38:
172             return float32
173         return float64
174 
175 
176 def is_ndarray(array):
177     """Check if array is a ndarray."""
178     import numpy as np
179 
180     return isinstance(array, np.ndarray) or hasattr(array, '__array__')
181 
182 
183 def can_cast_dtype(values, dtype):
184     """Test if values can be cast to dtype without loss of information.
185 
186     Parameters
187     ----------
188     values: list-like
189     dtype: numpy.dtype or string
190 
191     Returns
192     -------
193     boolean
194         True if values can be cast to data type.
195     """
196     import numpy as np
197 
198     if not is_ndarray(values):
199         values = np.array(values)
200 
201     if values.dtype.name == _getnpdtype(dtype).name:
202         return True
203 
204     elif values.dtype.kind == 'f':
205         return np.allclose(values, values.astype(dtype), equal_nan=True)
206 
207     else:
208         return np.array_equal(values, values.astype(dtype))
209 
210 
211 def validate_dtype(values, valid_dtypes):
212     """Test if dtype of values is one of valid_dtypes.
213 
214     Parameters
215     ----------
216     values: list-like
217     valid_dtypes: list-like
218         list of valid dtype strings, e.g., ('int16', 'int32')
219 
220     Returns
221     -------
222     boolean:
223         True if dtype of values is one of valid_dtypes
224     """
225     import numpy as np
226 
227     if not is_ndarray(values):
228         values = np.array(values)
229 
230     return (values.dtype.name in valid_dtypes or
231             get_minimum_dtype(values) in valid_dtypes)
232 
233 
234 def _is_complex_int(dtype):
235     return isinstance(dtype, str) and dtype.startswith("complex_int")
236 
237 
238 def _getnpdtype(dtype):
239     import numpy as np
240     if _is_complex_int(dtype):
241         return np.dtype("complex64")
242     else:
243         return np.dtype(dtype)
244
```
--- 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/rasterio/dtypes.py b/rasterio/dtypes.py
--- a/rasterio/dtypes.py
+++ b/rasterio/dtypes.py
@@ -10,6 +10,7 @@
 from rasterio.env import GDALVersion
 
 _GDAL_AT_LEAST_35 = GDALVersion.runtime().at_least("3.5")
+_GDAL_AT_LEAST_37 = GDALVersion.runtime().at_least("3.7")
 
 bool_ = 'bool'
 ubyte = uint8 = 'uint8'
@@ -47,10 +48,15 @@
     dtype_fwd[12] = int64 # GDT_Int64
     dtype_fwd[13] = uint64 # GDT_UInt64
 
+if _GDAL_AT_LEAST_37:
+    dtype_fwd[14] = sbyte # GDT_Int8
+
 dtype_rev = dict((v, k) for k, v in dtype_fwd.items())
 
 dtype_rev["uint8"] = 1
-dtype_rev["int8"] = 1
+if not _GDAL_AT_LEAST_37:
+    dtype_rev["int8"] = 1
+
 dtype_rev["complex"] = 11
 dtype_rev["complex_int16"] = 8
 
@@ -82,6 +88,9 @@
     typename_fwd[12] = 'Int64'
     typename_fwd[13] = 'UInt64'
 
+if _GDAL_AT_LEAST_37:
+    typename_fwd[14] = 'Int8'
+
 typename_rev = dict((v, k) for k, v in typename_fwd.items())
 
 dtype_ranges = {

{"golden_diff": "diff --git a/rasterio/dtypes.py b/rasterio/dtypes.py\n--- a/rasterio/dtypes.py\n+++ b/rasterio/dtypes.py\n@@ -10,6 +10,7 @@\n from rasterio.env import GDALVersion\n \n _GDAL_AT_LEAST_35 = GDALVersion.runtime().at_least(\"3.5\")\n+_GDAL_AT_LEAST_37 = GDALVersion.runtime().at_least(\"3.7\")\n \n bool_ = 'bool'\n ubyte = uint8 = 'uint8'\n@@ -47,10 +48,15 @@\n     dtype_fwd[12] = int64 # GDT_Int64\n     dtype_fwd[13] = uint64 # GDT_UInt64\n \n+if _GDAL_AT_LEAST_37:\n+    dtype_fwd[14] = sbyte # GDT_Int8\n+\n dtype_rev = dict((v, k) for k, v in dtype_fwd.items())\n \n dtype_rev[\"uint8\"] = 1\n-dtype_rev[\"int8\"] = 1\n+if not _GDAL_AT_LEAST_37:\n+    dtype_rev[\"int8\"] = 1\n+\n dtype_rev[\"complex\"] = 11\n dtype_rev[\"complex_int16\"] = 8\n \n@@ -82,6 +88,9 @@\n     typename_fwd[12] = 'Int64'\n     typename_fwd[13] = 'UInt64'\n \n+if _GDAL_AT_LEAST_37:\n+    typename_fwd[14] = 'Int8'\n+\n typename_rev = dict((v, k) for k, v in typename_fwd.items())\n \n dtype_ranges = {\n", "issue": "ENH: Add support for RFC 87: Signed int8 data type for raster\n        Cf https://github.com/OSGeo/gdal/pull/6634 \"RFC 87: Signed int8 data type for raster\" that will likely be implemented in GDAL 3.7\r\n\r\n_Originally posted by @rouault in https://github.com/rasterio/rasterio/issues/1595#issuecomment-1307086052_\r\n      \n", "before_files": [{"content": "\"\"\"Mapping of GDAL to Numpy data types.\n\nSince 0.13 we are not importing numpy here and data types are strings.\nHappily strings can be used throughout Numpy and so existing code will\nnot break.\n\n\"\"\"\nimport numpy\n\nfrom rasterio.env import GDALVersion\n\n_GDAL_AT_LEAST_35 = GDALVersion.runtime().at_least(\"3.5\")\n\nbool_ = 'bool'\nubyte = uint8 = 'uint8'\nsbyte = int8 = 'int8'\nuint16 = 'uint16'\nint16 = 'int16'\nuint32 = 'uint32'\nint32 = 'int32'\nuint64 = 'uint64'\nint64 = 'int64'\nfloat32 = 'float32'\nfloat64 = 'float64'\ncomplex_ = 'complex'\ncomplex64 = 'complex64'\ncomplex128 = 'complex128'\n\ncomplex_int16 = \"complex_int16\"\n\ndtype_fwd = {\n    0: None,  # GDT_Unknown\n    1: ubyte,  # GDT_Byte\n    2: uint16,  # GDT_UInt16\n    3: int16,  # GDT_Int16\n    4: uint32,  # GDT_UInt32\n    5: int32,  # GDT_Int32\n    6: float32,  # GDT_Float32\n    7: float64,  # GDT_Float64\n    8: complex_int16,  # GDT_CInt16\n    9: complex64,  # GDT_CInt32\n    10: complex64,  # GDT_CFloat32\n    11: complex128,  # GDT_CFloat64\n}\n\nif _GDAL_AT_LEAST_35:\n    dtype_fwd[12] = int64 # GDT_Int64\n    dtype_fwd[13] = uint64 # GDT_UInt64\n\ndtype_rev = dict((v, k) for k, v in dtype_fwd.items())\n\ndtype_rev[\"uint8\"] = 1\ndtype_rev[\"int8\"] = 1\ndtype_rev[\"complex\"] = 11\ndtype_rev[\"complex_int16\"] = 8\n\n\ndef _get_gdal_dtype(type_name):\n    try:\n        return dtype_rev[type_name]\n    except KeyError:\n        raise TypeError(\n            f\"Unsupported data type {type_name}. \"\n            f\"Allowed data types: {list(dtype_rev)}.\"\n        )\n\ntypename_fwd = {\n    0: 'Unknown',\n    1: 'Byte',\n    2: 'UInt16',\n    3: 'Int16',\n    4: 'UInt32',\n    5: 'Int32',\n    6: 'Float32',\n    7: 'Float64',\n    8: 'CInt16',\n    9: 'CInt32',\n    10: 'CFloat32',\n    11: 'CFloat64'}\n\nif _GDAL_AT_LEAST_35:\n    typename_fwd[12] = 'Int64'\n    typename_fwd[13] = 'UInt64'\n\ntypename_rev = dict((v, k) for k, v in typename_fwd.items())\n\ndtype_ranges = {\n    'int8': (-128, 127),\n    'uint8': (0, 255),\n    'uint16': (0, 65535),\n    'int16': (-32768, 32767),\n    'uint32': (0, 4294967295),\n    'int32': (-2147483648, 2147483647),\n    'float32': (-3.4028235e+38, 3.4028235e+38),\n    'float64': (-1.7976931348623157e+308, 1.7976931348623157e+308)}\n\nif _GDAL_AT_LEAST_35:\n    dtype_ranges['int64'] = (-9223372036854775808, 9223372036854775807)\n    dtype_ranges['uint64'] = (0, 18446744073709551615)\n\n\ndef in_dtype_range(value, dtype):\n    \"\"\"\n    Check if the value is within the dtype range\n    \"\"\"\n    if numpy.dtype(dtype).kind == \"f\" and (numpy.isinf(value) or numpy.isnan(value)):\n        return True\n    range_min, range_max = dtype_ranges[dtype]\n    return range_min <= value <= range_max\n\n\ndef _gdal_typename(dt):\n    try:\n        return typename_fwd[dtype_rev[dt]]\n    except KeyError:\n        return typename_fwd[dtype_rev[dt().dtype.name]]\n\n\ndef check_dtype(dt):\n    \"\"\"Check if dtype is a known dtype.\"\"\"\n    if str(dt) in dtype_rev:\n        return True\n    elif callable(dt) and str(dt().dtype) in dtype_rev:\n        return True\n    return False\n\n\ndef get_minimum_dtype(values):\n    \"\"\"Determine minimum type to represent values.\n\n    Uses range checking to determine the minimum integer or floating point\n    data type required to represent values.\n\n    Parameters\n    ----------\n    values: list-like\n\n\n    Returns\n    -------\n    rasterio dtype string\n    \"\"\"\n    import numpy as np\n\n    if not is_ndarray(values):\n        values = np.array(values)\n\n    min_value = values.min()\n    max_value = values.max()\n\n    if values.dtype.kind in ('i', 'u'):\n        if min_value >= 0:\n            if max_value <= 255:\n                return uint8\n            elif max_value <= 65535:\n                return uint16\n            elif max_value <= 4294967295:\n                return uint32\n            if not _GDAL_AT_LEAST_35:\n                raise ValueError(\"Values out of range for supported dtypes\")\n            return uint64\n        elif min_value >= -32768 and max_value <= 32767:\n            return int16\n        elif min_value >= -2147483648 and max_value <= 2147483647:\n            return int32\n        if not _GDAL_AT_LEAST_35:\n            raise ValueError(\"Values out of range for supported dtypes\")\n        return int64\n\n    else:\n        if min_value >= -3.4028235e+38 and max_value <= 3.4028235e+38:\n            return float32\n        return float64\n\n\ndef is_ndarray(array):\n    \"\"\"Check if array is a ndarray.\"\"\"\n    import numpy as np\n\n    return isinstance(array, np.ndarray) or hasattr(array, '__array__')\n\n\ndef can_cast_dtype(values, dtype):\n    \"\"\"Test if values can be cast to dtype without loss of information.\n\n    Parameters\n    ----------\n    values: list-like\n    dtype: numpy.dtype or string\n\n    Returns\n    -------\n    boolean\n        True if values can be cast to data type.\n    \"\"\"\n    import numpy as np\n\n    if not is_ndarray(values):\n        values = np.array(values)\n\n    if values.dtype.name == _getnpdtype(dtype).name:\n        return True\n\n    elif values.dtype.kind == 'f':\n        return np.allclose(values, values.astype(dtype), equal_nan=True)\n\n    else:\n        return np.array_equal(values, values.astype(dtype))\n\n\ndef validate_dtype(values, valid_dtypes):\n    \"\"\"Test if dtype of values is one of valid_dtypes.\n\n    Parameters\n    ----------\n    values: list-like\n    valid_dtypes: list-like\n        list of valid dtype strings, e.g., ('int16', 'int32')\n\n    Returns\n    -------\n    boolean:\n        True if dtype of values is one of valid_dtypes\n    \"\"\"\n    import numpy as np\n\n    if not is_ndarray(values):\n        values = np.array(values)\n\n    return (values.dtype.name in valid_dtypes or\n            get_minimum_dtype(values) in valid_dtypes)\n\n\ndef _is_complex_int(dtype):\n    return isinstance(dtype, str) and dtype.startswith(\"complex_int\")\n\n\ndef _getnpdtype(dtype):\n    import numpy as np\n    if _is_complex_int(dtype):\n        return np.dtype(\"complex64\")\n    else:\n        return np.dtype(dtype)\n", "path": "rasterio/dtypes.py"}], "after_files": [{"content": "\"\"\"Mapping of GDAL to Numpy data types.\n\nSince 0.13 we are not importing numpy here and data types are strings.\nHappily strings can be used throughout Numpy and so existing code will\nnot break.\n\n\"\"\"\nimport numpy\n\nfrom rasterio.env import GDALVersion\n\n_GDAL_AT_LEAST_35 = GDALVersion.runtime().at_least(\"3.5\")\n_GDAL_AT_LEAST_37 = GDALVersion.runtime().at_least(\"3.7\")\n\nbool_ = 'bool'\nubyte = uint8 = 'uint8'\nsbyte = int8 = 'int8'\nuint16 = 'uint16'\nint16 = 'int16'\nuint32 = 'uint32'\nint32 = 'int32'\nuint64 = 'uint64'\nint64 = 'int64'\nfloat32 = 'float32'\nfloat64 = 'float64'\ncomplex_ = 'complex'\ncomplex64 = 'complex64'\ncomplex128 = 'complex128'\n\ncomplex_int16 = \"complex_int16\"\n\ndtype_fwd = {\n    0: None,  # GDT_Unknown\n    1: ubyte,  # GDT_Byte\n    2: uint16,  # GDT_UInt16\n    3: int16,  # GDT_Int16\n    4: uint32,  # GDT_UInt32\n    5: int32,  # GDT_Int32\n    6: float32,  # GDT_Float32\n    7: float64,  # GDT_Float64\n    8: complex_int16,  # GDT_CInt16\n    9: complex64,  # GDT_CInt32\n    10: complex64,  # GDT_CFloat32\n    11: complex128,  # GDT_CFloat64\n}\n\nif _GDAL_AT_LEAST_35:\n    dtype_fwd[12] = int64 # GDT_Int64\n    dtype_fwd[13] = uint64 # GDT_UInt64\n\nif _GDAL_AT_LEAST_37:\n    dtype_fwd[14] = sbyte # GDT_Int8\n\ndtype_rev = dict((v, k) for k, v in dtype_fwd.items())\n\ndtype_rev[\"uint8\"] = 1\nif not _GDAL_AT_LEAST_37:\n    dtype_rev[\"int8\"] = 1\n\ndtype_rev[\"complex\"] = 11\ndtype_rev[\"complex_int16\"] = 8\n\n\ndef _get_gdal_dtype(type_name):\n    try:\n        return dtype_rev[type_name]\n    except KeyError:\n        raise TypeError(\n            f\"Unsupported data type {type_name}. \"\n            f\"Allowed data types: {list(dtype_rev)}.\"\n        )\n\ntypename_fwd = {\n    0: 'Unknown',\n    1: 'Byte',\n    2: 'UInt16',\n    3: 'Int16',\n    4: 'UInt32',\n    5: 'Int32',\n    6: 'Float32',\n    7: 'Float64',\n    8: 'CInt16',\n    9: 'CInt32',\n    10: 'CFloat32',\n    11: 'CFloat64'}\n\nif _GDAL_AT_LEAST_35:\n    typename_fwd[12] = 'Int64'\n    typename_fwd[13] = 'UInt64'\n\nif _GDAL_AT_LEAST_37:\n    typename_fwd[14] = 'Int8'\n\ntypename_rev = dict((v, k) for k, v in typename_fwd.items())\n\ndtype_ranges = {\n    'int8': (-128, 127),\n    'uint8': (0, 255),\n    'uint16': (0, 65535),\n    'int16': (-32768, 32767),\n    'uint32': (0, 4294967295),\n    'int32': (-2147483648, 2147483647),\n    'float32': (-3.4028235e+38, 3.4028235e+38),\n    'float64': (-1.7976931348623157e+308, 1.7976931348623157e+308)}\n\nif _GDAL_AT_LEAST_35:\n    dtype_ranges['int64'] = (-9223372036854775808, 9223372036854775807)\n    dtype_ranges['uint64'] = (0, 18446744073709551615)\n\n\ndef in_dtype_range(value, dtype):\n    \"\"\"\n    Check if the value is within the dtype range\n    \"\"\"\n    if numpy.dtype(dtype).kind == \"f\" and (numpy.isinf(value) or numpy.isnan(value)):\n        return True\n    range_min, range_max = dtype_ranges[dtype]\n    return range_min <= value <= range_max\n\n\ndef _gdal_typename(dt):\n    try:\n        return typename_fwd[dtype_rev[dt]]\n    except KeyError:\n        return typename_fwd[dtype_rev[dt().dtype.name]]\n\n\ndef check_dtype(dt):\n    \"\"\"Check if dtype is a known dtype.\"\"\"\n    if str(dt) in dtype_rev:\n        return True\n    elif callable(dt) and str(dt().dtype) in dtype_rev:\n        return True\n    return False\n\n\ndef get_minimum_dtype(values):\n    \"\"\"Determine minimum type to represent values.\n\n    Uses range checking to determine the minimum integer or floating point\n    data type required to represent values.\n\n    Parameters\n    ----------\n    values: list-like\n\n\n    Returns\n    -------\n    rasterio dtype string\n    \"\"\"\n    import numpy as np\n\n    if not is_ndarray(values):\n        values = np.array(values)\n\n    min_value = values.min()\n    max_value = values.max()\n\n    if values.dtype.kind in ('i', 'u'):\n        if min_value >= 0:\n            if max_value <= 255:\n                return uint8\n            elif max_value <= 65535:\n                return uint16\n            elif max_value <= 4294967295:\n                return uint32\n            if not _GDAL_AT_LEAST_35:\n                raise ValueError(\"Values out of range for supported dtypes\")\n            return uint64\n        elif min_value >= -32768 and max_value <= 32767:\n            return int16\n        elif min_value >= -2147483648 and max_value <= 2147483647:\n            return int32\n        if not _GDAL_AT_LEAST_35:\n            raise ValueError(\"Values out of range for supported dtypes\")\n        return int64\n\n    else:\n        if min_value >= -3.4028235e+38 and max_value <= 3.4028235e+38:\n            return float32\n        return float64\n\n\ndef is_ndarray(array):\n    \"\"\"Check if array is a ndarray.\"\"\"\n    import numpy as np\n\n    return isinstance(array, np.ndarray) or hasattr(array, '__array__')\n\n\ndef can_cast_dtype(values, dtype):\n    \"\"\"Test if values can be cast to dtype without loss of information.\n\n    Parameters\n    ----------\n    values: list-like\n    dtype: numpy.dtype or string\n\n    Returns\n    -------\n    boolean\n        True if values can be cast to data type.\n    \"\"\"\n    import numpy as np\n\n    if not is_ndarray(values):\n        values = np.array(values)\n\n    if values.dtype.name == _getnpdtype(dtype).name:\n        return True\n\n    elif values.dtype.kind == 'f':\n        return np.allclose(values, values.astype(dtype), equal_nan=True)\n\n    else:\n        return np.array_equal(values, values.astype(dtype))\n\n\ndef validate_dtype(values, valid_dtypes):\n    \"\"\"Test if dtype of values is one of valid_dtypes.\n\n    Parameters\n    ----------\n    values: list-like\n    valid_dtypes: list-like\n        list of valid dtype strings, e.g., ('int16', 'int32')\n\n    Returns\n    -------\n    boolean:\n        True if dtype of values is one of valid_dtypes\n    \"\"\"\n    import numpy as np\n\n    if not is_ndarray(values):\n        values = np.array(values)\n\n    return (values.dtype.name in valid_dtypes or\n            get_minimum_dtype(values) in valid_dtypes)\n\n\ndef _is_complex_int(dtype):\n    return isinstance(dtype, str) and dtype.startswith(\"complex_int\")\n\n\ndef _getnpdtype(dtype):\n    import numpy as np\n    if _is_complex_int(dtype):\n        return np.dtype(\"complex64\")\n    else:\n        return np.dtype(dtype)\n", "path": "rasterio/dtypes.py"}]}