We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
shapes from data types other than uint8
The companion to #136.


--- 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/features.py`
Content:
```
1 """Functions for working with features in a raster dataset."""
2 
3 import json
4 import logging
5 import time
6 import warnings
7 
8 import numpy as np
9 
10 import rasterio
11 from rasterio._features import _shapes, _sieve, _rasterize
12 from rasterio.transform import IDENTITY, guard_transform
13 from rasterio.dtypes import get_minimum_int_dtype
14 
15 
16 log = logging.getLogger('rasterio')
17 class NullHandler(logging.Handler):
18     def emit(self, record):
19         pass
20 log.addHandler(NullHandler())
21 
22 
23 def shapes(image, mask=None, connectivity=4, transform=IDENTITY):
24     """Yields a (shape, image_value) pair for each feature in the image.
25     
26     The shapes are GeoJSON-like dicts and the image values are ints.
27     
28     Features are found using a connected-component labeling algorithm.
29 
30     The image must be of unsigned 8-bit integer (rasterio.byte or
31     numpy.uint8) data type. If a mask is provided, pixels for which the
32     mask is `False` will be excluded from feature generation.
33     """
34     if np.dtype(image.dtype) != np.dtype(rasterio.ubyte):
35         raise ValueError("Image must be dtype uint8/ubyte")
36 
37     if mask is not None and np.dtype(mask.dtype) != np.dtype(rasterio.bool_):
38         raise ValueError("Mask must be dtype rasterio.bool_")
39 
40     if connectivity not in (4, 8):
41         raise ValueError("Connectivity Option must be 4 or 8")
42 
43     transform = guard_transform(transform)
44 
45     with rasterio.drivers():
46         for s, v in _shapes(image, mask, connectivity, transform.to_gdal()):
47             yield s, v
48 
49 
50 def sieve(image, size, connectivity=4, output=None):
51     """Returns a copy of the image, but with smaller features removed.
52 
53     Features smaller than the specified size have their pixel value
54     replaced by that of the largest neighboring features.
55     
56     The image must be of unsigned 8-bit integer (rasterio.byte or
57     numpy.uint8) data type.
58     """
59     if np.dtype(image.dtype) != np.dtype(rasterio.ubyte):
60         raise ValueError("Image must be dtype uint8/ubyte")
61 
62     if output is not None and (
63             np.dtype(output.dtype) != np.dtype(rasterio.ubyte)):
64         raise ValueError("Output must be dtype uint8/ubyte")
65 
66     with rasterio.drivers():
67         return _sieve(image, size, connectivity)
68 
69 
70 def rasterize(
71         shapes, 
72         out_shape=None,
73         fill=0,
74         output=None,
75         transform=IDENTITY,
76         all_touched=False,
77         default_value=1,
78         dtype=None):
79     """Returns an image array with points, lines, or polygons burned in.
80 
81     A different value may be specified for each shape.  The shapes may
82     be georeferenced or may have image coordinates. An existing image
83     array may be provided, or one may be created. By default, the center
84     of image elements determines whether they are updated, but all
85     touched elements may be optionally updated.
86 
87     Valid data types are: int16, int32, uint8, uint16, uint32, float32, float64
88 
89     :param shapes: an iterator over Fiona style geometry objects (with a default
90     value of default_value) or an iterator over (geometry, value) pairs.
91 
92     :param transform: GDAL style geotransform to be applied to the
93     image.
94 
95     :param out_shape: shape of created image array
96     :param fill: fill value for created image array
97     :param output: alternatively, an existing image array
98 
99     :param all_touched: if True, will rasterize all pixels touched, 
100     otherwise will use GDAL default method.
101     :param default_value: value burned in for shapes if not provided as part
102     of shapes.
103     """
104 
105     valid_dtypes = ('int16', 'int32', 'uint8', 'uint16', 'uint32', 'float32',
106                     'float64')
107 
108     def get_valid_dtype(values):
109         values_dtype = values.dtype
110         if values_dtype.kind == 'i':
111             values_dtype = np.dtype(get_minimum_int_dtype(values))
112         if values_dtype.name in valid_dtypes:
113             return values_dtype
114         return None
115 
116     def can_cast_dtype(values, dtype):
117         if values.dtype.name == np.dtype(dtype).name:
118             return True
119         elif values.dtype.kind == 'f':
120             return np.allclose(values, values.astype(dtype))
121         else:
122             return np.array_equal(values, values.astype(dtype))
123 
124     if fill != 0:
125         fill_array = np.array([fill])
126         if get_valid_dtype(fill_array) is None:
127             raise ValueError('fill must be one of these types: %s'
128                              % (', '.join(valid_dtypes)))
129         elif dtype is not None and not can_cast_dtype(fill_array, dtype):
130             raise ValueError('fill value cannot be cast to specified dtype')
131 
132 
133     if default_value != 1:
134         default_value_array = np.array([default_value])
135         if get_valid_dtype(default_value_array) is None:
136             raise ValueError('default_value must be one of these types: %s'
137                              % (', '.join(valid_dtypes)))
138         elif dtype is not None and not can_cast_dtype(default_value_array,
139                                                       dtype):
140             raise ValueError('default_value cannot be cast to specified dtype')
141 
142     valid_shapes = []
143     shape_values = []
144     for index, item in enumerate(shapes):
145         try:
146             if isinstance(item, (tuple, list)):
147                 geom, value = item
148             else:
149                 geom = item
150                 value = default_value
151             geom = getattr(geom, '__geo_interface__', None) or geom
152             if (not isinstance(geom, dict) or
153                 'type' not in geom or 'coordinates' not in geom):
154                 raise ValueError(
155                     'Object %r at index %d is not a geometry object' %
156                     (geom, index))
157             valid_shapes.append((geom, value))
158             shape_values.append(value)
159         except Exception:
160             log.exception('Exception caught, skipping shape %d', index)
161 
162     if not valid_shapes:
163         raise ValueError('No valid shapes found for rasterize.  Shapes must be '
164                          'valid geometry objects')
165 
166     shape_values = np.array(shape_values)
167     values_dtype = get_valid_dtype(shape_values)
168     if values_dtype is None:
169         raise ValueError('shape values must be one of these dtypes: %s' %
170                          (', '.join(valid_dtypes)))
171 
172     if dtype is None:
173         dtype = values_dtype
174     elif np.dtype(dtype).name not in valid_dtypes:
175         raise ValueError('dtype must be one of: %s' % (', '.join(valid_dtypes)))
176     elif not can_cast_dtype(shape_values, dtype):
177         raise ValueError('shape values could not be cast to specified dtype')
178 
179     if output is not None:
180         if np.dtype(output.dtype).name not in valid_dtypes:
181             raise ValueError('Output image dtype must be one of: %s' 
182                              % (', '.join(valid_dtypes)))
183         if not can_cast_dtype(shape_values, output.dtype):
184             raise ValueError('shape values cannot be cast to dtype of output '
185                              'image')
186 
187     elif out_shape is not None:
188         output = np.empty(out_shape, dtype=dtype)
189         output.fill(fill)
190     else:
191         raise ValueError('Either an output shape or image must be provided')
192     
193     transform = guard_transform(transform)
194 
195     with rasterio.drivers():
196         _rasterize(valid_shapes, output, transform.to_gdal(), all_touched)
197     
198     return output
199 
200
```
--- 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/features.py b/rasterio/features.py
--- a/rasterio/features.py
+++ b/rasterio/features.py
@@ -22,17 +22,26 @@
 
 def shapes(image, mask=None, connectivity=4, transform=IDENTITY):
     """Yields a (shape, image_value) pair for each feature in the image.
-    
-    The shapes are GeoJSON-like dicts and the image values are ints.
-    
+
+    The shapes are GeoJSON-like dicts and the image values are ints or floats
+    depending on the data type of the image.
+
     Features are found using a connected-component labeling algorithm.
 
-    The image must be of unsigned 8-bit integer (rasterio.byte or
-    numpy.uint8) data type. If a mask is provided, pixels for which the
-    mask is `False` will be excluded from feature generation.
+    The image must be one of int16, int32, uint8, uint16, float32 data types.
+    Note: due to floating point precision issues, the floating point values
+    returned from a floating point image may not exactly match the original
+    values.
+
+    If a mask is provided, pixels for which the mask is `False` will be
+    excluded from feature generation.
     """
-    if np.dtype(image.dtype) != np.dtype(rasterio.ubyte):
-        raise ValueError("Image must be dtype uint8/ubyte")
+
+    valid_dtypes = ('int16', 'int32', 'uint8', 'uint16', 'float32')
+
+    if np.dtype(image.dtype).name not in valid_dtypes:
+        raise ValueError('image dtype must be one of: %s'
+                         % (', '.join(valid_dtypes)))
 
     if mask is not None and np.dtype(mask.dtype) != np.dtype(rasterio.bool_):
         raise ValueError("Mask must be dtype rasterio.bool_")
@@ -52,7 +61,7 @@
 
     Features smaller than the specified size have their pixel value
     replaced by that of the largest neighboring features.
-    
+
     The image must be of unsigned 8-bit integer (rasterio.byte or
     numpy.uint8) data type.
     """
@@ -68,7 +77,7 @@
 
 
 def rasterize(
-        shapes, 
+        shapes,
         out_shape=None,
         fill=0,
         output=None,
@@ -96,7 +105,7 @@
     :param fill: fill value for created image array
     :param output: alternatively, an existing image array
 
-    :param all_touched: if True, will rasterize all pixels touched, 
+    :param all_touched: if True, will rasterize all pixels touched,
     otherwise will use GDAL default method.
     :param default_value: value burned in for shapes if not provided as part
     of shapes.
@@ -178,7 +187,7 @@
 
     if output is not None:
         if np.dtype(output.dtype).name not in valid_dtypes:
-            raise ValueError('Output image dtype must be one of: %s' 
+            raise ValueError('Output image dtype must be one of: %s'
                              % (', '.join(valid_dtypes)))
         if not can_cast_dtype(shape_values, output.dtype):
             raise ValueError('shape values cannot be cast to dtype of output '

{"golden_diff": "diff --git a/rasterio/features.py b/rasterio/features.py\n--- a/rasterio/features.py\n+++ b/rasterio/features.py\n@@ -22,17 +22,26 @@\n \n def shapes(image, mask=None, connectivity=4, transform=IDENTITY):\n     \"\"\"Yields a (shape, image_value) pair for each feature in the image.\n-    \n-    The shapes are GeoJSON-like dicts and the image values are ints.\n-    \n+\n+    The shapes are GeoJSON-like dicts and the image values are ints or floats\n+    depending on the data type of the image.\n+\n     Features are found using a connected-component labeling algorithm.\n \n-    The image must be of unsigned 8-bit integer (rasterio.byte or\n-    numpy.uint8) data type. If a mask is provided, pixels for which the\n-    mask is `False` will be excluded from feature generation.\n+    The image must be one of int16, int32, uint8, uint16, float32 data types.\n+    Note: due to floating point precision issues, the floating point values\n+    returned from a floating point image may not exactly match the original\n+    values.\n+\n+    If a mask is provided, pixels for which the mask is `False` will be\n+    excluded from feature generation.\n     \"\"\"\n-    if np.dtype(image.dtype) != np.dtype(rasterio.ubyte):\n-        raise ValueError(\"Image must be dtype uint8/ubyte\")\n+\n+    valid_dtypes = ('int16', 'int32', 'uint8', 'uint16', 'float32')\n+\n+    if np.dtype(image.dtype).name not in valid_dtypes:\n+        raise ValueError('image dtype must be one of: %s'\n+                         % (', '.join(valid_dtypes)))\n \n     if mask is not None and np.dtype(mask.dtype) != np.dtype(rasterio.bool_):\n         raise ValueError(\"Mask must be dtype rasterio.bool_\")\n@@ -52,7 +61,7 @@\n \n     Features smaller than the specified size have their pixel value\n     replaced by that of the largest neighboring features.\n-    \n+\n     The image must be of unsigned 8-bit integer (rasterio.byte or\n     numpy.uint8) data type.\n     \"\"\"\n@@ -68,7 +77,7 @@\n \n \n def rasterize(\n-        shapes, \n+        shapes,\n         out_shape=None,\n         fill=0,\n         output=None,\n@@ -96,7 +105,7 @@\n     :param fill: fill value for created image array\n     :param output: alternatively, an existing image array\n \n-    :param all_touched: if True, will rasterize all pixels touched, \n+    :param all_touched: if True, will rasterize all pixels touched,\n     otherwise will use GDAL default method.\n     :param default_value: value burned in for shapes if not provided as part\n     of shapes.\n@@ -178,7 +187,7 @@\n \n     if output is not None:\n         if np.dtype(output.dtype).name not in valid_dtypes:\n-            raise ValueError('Output image dtype must be one of: %s' \n+            raise ValueError('Output image dtype must be one of: %s'\n                              % (', '.join(valid_dtypes)))\n         if not can_cast_dtype(shape_values, output.dtype):\n             raise ValueError('shape values cannot be cast to dtype of output '\n", "issue": "shapes from data types other than uint8\nThe companion to #136.\n\n", "before_files": [{"content": "\"\"\"Functions for working with features in a raster dataset.\"\"\"\n\nimport json\nimport logging\nimport time\nimport warnings\n\nimport numpy as np\n\nimport rasterio\nfrom rasterio._features import _shapes, _sieve, _rasterize\nfrom rasterio.transform import IDENTITY, guard_transform\nfrom rasterio.dtypes import get_minimum_int_dtype\n\n\nlog = logging.getLogger('rasterio')\nclass NullHandler(logging.Handler):\n    def emit(self, record):\n        pass\nlog.addHandler(NullHandler())\n\n\ndef shapes(image, mask=None, connectivity=4, transform=IDENTITY):\n    \"\"\"Yields a (shape, image_value) pair for each feature in the image.\n    \n    The shapes are GeoJSON-like dicts and the image values are ints.\n    \n    Features are found using a connected-component labeling algorithm.\n\n    The image must be of unsigned 8-bit integer (rasterio.byte or\n    numpy.uint8) data type. If a mask is provided, pixels for which the\n    mask is `False` will be excluded from feature generation.\n    \"\"\"\n    if np.dtype(image.dtype) != np.dtype(rasterio.ubyte):\n        raise ValueError(\"Image must be dtype uint8/ubyte\")\n\n    if mask is not None and np.dtype(mask.dtype) != np.dtype(rasterio.bool_):\n        raise ValueError(\"Mask must be dtype rasterio.bool_\")\n\n    if connectivity not in (4, 8):\n        raise ValueError(\"Connectivity Option must be 4 or 8\")\n\n    transform = guard_transform(transform)\n\n    with rasterio.drivers():\n        for s, v in _shapes(image, mask, connectivity, transform.to_gdal()):\n            yield s, v\n\n\ndef sieve(image, size, connectivity=4, output=None):\n    \"\"\"Returns a copy of the image, but with smaller features removed.\n\n    Features smaller than the specified size have their pixel value\n    replaced by that of the largest neighboring features.\n    \n    The image must be of unsigned 8-bit integer (rasterio.byte or\n    numpy.uint8) data type.\n    \"\"\"\n    if np.dtype(image.dtype) != np.dtype(rasterio.ubyte):\n        raise ValueError(\"Image must be dtype uint8/ubyte\")\n\n    if output is not None and (\n            np.dtype(output.dtype) != np.dtype(rasterio.ubyte)):\n        raise ValueError(\"Output must be dtype uint8/ubyte\")\n\n    with rasterio.drivers():\n        return _sieve(image, size, connectivity)\n\n\ndef rasterize(\n        shapes, \n        out_shape=None,\n        fill=0,\n        output=None,\n        transform=IDENTITY,\n        all_touched=False,\n        default_value=1,\n        dtype=None):\n    \"\"\"Returns an image array with points, lines, or polygons burned in.\n\n    A different value may be specified for each shape.  The shapes may\n    be georeferenced or may have image coordinates. An existing image\n    array may be provided, or one may be created. By default, the center\n    of image elements determines whether they are updated, but all\n    touched elements may be optionally updated.\n\n    Valid data types are: int16, int32, uint8, uint16, uint32, float32, float64\n\n    :param shapes: an iterator over Fiona style geometry objects (with a default\n    value of default_value) or an iterator over (geometry, value) pairs.\n\n    :param transform: GDAL style geotransform to be applied to the\n    image.\n\n    :param out_shape: shape of created image array\n    :param fill: fill value for created image array\n    :param output: alternatively, an existing image array\n\n    :param all_touched: if True, will rasterize all pixels touched, \n    otherwise will use GDAL default method.\n    :param default_value: value burned in for shapes if not provided as part\n    of shapes.\n    \"\"\"\n\n    valid_dtypes = ('int16', 'int32', 'uint8', 'uint16', 'uint32', 'float32',\n                    'float64')\n\n    def get_valid_dtype(values):\n        values_dtype = values.dtype\n        if values_dtype.kind == 'i':\n            values_dtype = np.dtype(get_minimum_int_dtype(values))\n        if values_dtype.name in valid_dtypes:\n            return values_dtype\n        return None\n\n    def can_cast_dtype(values, dtype):\n        if values.dtype.name == np.dtype(dtype).name:\n            return True\n        elif values.dtype.kind == 'f':\n            return np.allclose(values, values.astype(dtype))\n        else:\n            return np.array_equal(values, values.astype(dtype))\n\n    if fill != 0:\n        fill_array = np.array([fill])\n        if get_valid_dtype(fill_array) is None:\n            raise ValueError('fill must be one of these types: %s'\n                             % (', '.join(valid_dtypes)))\n        elif dtype is not None and not can_cast_dtype(fill_array, dtype):\n            raise ValueError('fill value cannot be cast to specified dtype')\n\n\n    if default_value != 1:\n        default_value_array = np.array([default_value])\n        if get_valid_dtype(default_value_array) is None:\n            raise ValueError('default_value must be one of these types: %s'\n                             % (', '.join(valid_dtypes)))\n        elif dtype is not None and not can_cast_dtype(default_value_array,\n                                                      dtype):\n            raise ValueError('default_value cannot be cast to specified dtype')\n\n    valid_shapes = []\n    shape_values = []\n    for index, item in enumerate(shapes):\n        try:\n            if isinstance(item, (tuple, list)):\n                geom, value = item\n            else:\n                geom = item\n                value = default_value\n            geom = getattr(geom, '__geo_interface__', None) or geom\n            if (not isinstance(geom, dict) or\n                'type' not in geom or 'coordinates' not in geom):\n                raise ValueError(\n                    'Object %r at index %d is not a geometry object' %\n                    (geom, index))\n            valid_shapes.append((geom, value))\n            shape_values.append(value)\n        except Exception:\n            log.exception('Exception caught, skipping shape %d', index)\n\n    if not valid_shapes:\n        raise ValueError('No valid shapes found for rasterize.  Shapes must be '\n                         'valid geometry objects')\n\n    shape_values = np.array(shape_values)\n    values_dtype = get_valid_dtype(shape_values)\n    if values_dtype is None:\n        raise ValueError('shape values must be one of these dtypes: %s' %\n                         (', '.join(valid_dtypes)))\n\n    if dtype is None:\n        dtype = values_dtype\n    elif np.dtype(dtype).name not in valid_dtypes:\n        raise ValueError('dtype must be one of: %s' % (', '.join(valid_dtypes)))\n    elif not can_cast_dtype(shape_values, dtype):\n        raise ValueError('shape values could not be cast to specified dtype')\n\n    if output is not None:\n        if np.dtype(output.dtype).name not in valid_dtypes:\n            raise ValueError('Output image dtype must be one of: %s' \n                             % (', '.join(valid_dtypes)))\n        if not can_cast_dtype(shape_values, output.dtype):\n            raise ValueError('shape values cannot be cast to dtype of output '\n                             'image')\n\n    elif out_shape is not None:\n        output = np.empty(out_shape, dtype=dtype)\n        output.fill(fill)\n    else:\n        raise ValueError('Either an output shape or image must be provided')\n    \n    transform = guard_transform(transform)\n\n    with rasterio.drivers():\n        _rasterize(valid_shapes, output, transform.to_gdal(), all_touched)\n    \n    return output\n\n", "path": "rasterio/features.py"}], "after_files": [{"content": "\"\"\"Functions for working with features in a raster dataset.\"\"\"\n\nimport json\nimport logging\nimport time\nimport warnings\n\nimport numpy as np\n\nimport rasterio\nfrom rasterio._features import _shapes, _sieve, _rasterize\nfrom rasterio.transform import IDENTITY, guard_transform\nfrom rasterio.dtypes import get_minimum_int_dtype\n\n\nlog = logging.getLogger('rasterio')\nclass NullHandler(logging.Handler):\n    def emit(self, record):\n        pass\nlog.addHandler(NullHandler())\n\n\ndef shapes(image, mask=None, connectivity=4, transform=IDENTITY):\n    \"\"\"Yields a (shape, image_value) pair for each feature in the image.\n\n    The shapes are GeoJSON-like dicts and the image values are ints or floats\n    depending on the data type of the image.\n\n    Features are found using a connected-component labeling algorithm.\n\n    The image must be one of int16, int32, uint8, uint16, float32 data types.\n    Note: due to floating point precision issues, the floating point values\n    returned from a floating point image may not exactly match the original\n    values.\n\n    If a mask is provided, pixels for which the mask is `False` will be\n    excluded from feature generation.\n    \"\"\"\n\n    valid_dtypes = ('int16', 'int32', 'uint8', 'uint16', 'float32')\n\n    if np.dtype(image.dtype).name not in valid_dtypes:\n        raise ValueError('image dtype must be one of: %s'\n                         % (', '.join(valid_dtypes)))\n\n    if mask is not None and np.dtype(mask.dtype) != np.dtype(rasterio.bool_):\n        raise ValueError(\"Mask must be dtype rasterio.bool_\")\n\n    if connectivity not in (4, 8):\n        raise ValueError(\"Connectivity Option must be 4 or 8\")\n\n    transform = guard_transform(transform)\n\n    with rasterio.drivers():\n        for s, v in _shapes(image, mask, connectivity, transform.to_gdal()):\n            yield s, v\n\n\ndef sieve(image, size, connectivity=4, output=None):\n    \"\"\"Returns a copy of the image, but with smaller features removed.\n\n    Features smaller than the specified size have their pixel value\n    replaced by that of the largest neighboring features.\n\n    The image must be of unsigned 8-bit integer (rasterio.byte or\n    numpy.uint8) data type.\n    \"\"\"\n    if np.dtype(image.dtype) != np.dtype(rasterio.ubyte):\n        raise ValueError(\"Image must be dtype uint8/ubyte\")\n\n    if output is not None and (\n            np.dtype(output.dtype) != np.dtype(rasterio.ubyte)):\n        raise ValueError(\"Output must be dtype uint8/ubyte\")\n\n    with rasterio.drivers():\n        return _sieve(image, size, connectivity)\n\n\ndef rasterize(\n        shapes,\n        out_shape=None,\n        fill=0,\n        output=None,\n        transform=IDENTITY,\n        all_touched=False,\n        default_value=1,\n        dtype=None):\n    \"\"\"Returns an image array with points, lines, or polygons burned in.\n\n    A different value may be specified for each shape.  The shapes may\n    be georeferenced or may have image coordinates. An existing image\n    array may be provided, or one may be created. By default, the center\n    of image elements determines whether they are updated, but all\n    touched elements may be optionally updated.\n\n    Valid data types are: int16, int32, uint8, uint16, uint32, float32, float64\n\n    :param shapes: an iterator over Fiona style geometry objects (with a default\n    value of default_value) or an iterator over (geometry, value) pairs.\n\n    :param transform: GDAL style geotransform to be applied to the\n    image.\n\n    :param out_shape: shape of created image array\n    :param fill: fill value for created image array\n    :param output: alternatively, an existing image array\n\n    :param all_touched: if True, will rasterize all pixels touched,\n    otherwise will use GDAL default method.\n    :param default_value: value burned in for shapes if not provided as part\n    of shapes.\n    \"\"\"\n\n    valid_dtypes = ('int16', 'int32', 'uint8', 'uint16', 'uint32', 'float32',\n                    'float64')\n\n    def get_valid_dtype(values):\n        values_dtype = values.dtype\n        if values_dtype.kind == 'i':\n            values_dtype = np.dtype(get_minimum_int_dtype(values))\n        if values_dtype.name in valid_dtypes:\n            return values_dtype\n        return None\n\n    def can_cast_dtype(values, dtype):\n        if values.dtype.name == np.dtype(dtype).name:\n            return True\n        elif values.dtype.kind == 'f':\n            return np.allclose(values, values.astype(dtype))\n        else:\n            return np.array_equal(values, values.astype(dtype))\n\n    if fill != 0:\n        fill_array = np.array([fill])\n        if get_valid_dtype(fill_array) is None:\n            raise ValueError('fill must be one of these types: %s'\n                             % (', '.join(valid_dtypes)))\n        elif dtype is not None and not can_cast_dtype(fill_array, dtype):\n            raise ValueError('fill value cannot be cast to specified dtype')\n\n\n    if default_value != 1:\n        default_value_array = np.array([default_value])\n        if get_valid_dtype(default_value_array) is None:\n            raise ValueError('default_value must be one of these types: %s'\n                             % (', '.join(valid_dtypes)))\n        elif dtype is not None and not can_cast_dtype(default_value_array,\n                                                      dtype):\n            raise ValueError('default_value cannot be cast to specified dtype')\n\n    valid_shapes = []\n    shape_values = []\n    for index, item in enumerate(shapes):\n        try:\n            if isinstance(item, (tuple, list)):\n                geom, value = item\n            else:\n                geom = item\n                value = default_value\n            geom = getattr(geom, '__geo_interface__', None) or geom\n            if (not isinstance(geom, dict) or\n                'type' not in geom or 'coordinates' not in geom):\n                raise ValueError(\n                    'Object %r at index %d is not a geometry object' %\n                    (geom, index))\n            valid_shapes.append((geom, value))\n            shape_values.append(value)\n        except Exception:\n            log.exception('Exception caught, skipping shape %d', index)\n\n    if not valid_shapes:\n        raise ValueError('No valid shapes found for rasterize.  Shapes must be '\n                         'valid geometry objects')\n\n    shape_values = np.array(shape_values)\n    values_dtype = get_valid_dtype(shape_values)\n    if values_dtype is None:\n        raise ValueError('shape values must be one of these dtypes: %s' %\n                         (', '.join(valid_dtypes)))\n\n    if dtype is None:\n        dtype = values_dtype\n    elif np.dtype(dtype).name not in valid_dtypes:\n        raise ValueError('dtype must be one of: %s' % (', '.join(valid_dtypes)))\n    elif not can_cast_dtype(shape_values, dtype):\n        raise ValueError('shape values could not be cast to specified dtype')\n\n    if output is not None:\n        if np.dtype(output.dtype).name not in valid_dtypes:\n            raise ValueError('Output image dtype must be one of: %s'\n                             % (', '.join(valid_dtypes)))\n        if not can_cast_dtype(shape_values, output.dtype):\n            raise ValueError('shape values cannot be cast to dtype of output '\n                             'image')\n\n    elif out_shape is not None:\n        output = np.empty(out_shape, dtype=dtype)\n        output.fill(fill)\n    else:\n        raise ValueError('Either an output shape or image must be provided')\n    \n    transform = guard_transform(transform)\n\n    with rasterio.drivers():\n        _rasterize(valid_shapes, output, transform.to_gdal(), all_touched)\n    \n    return output\n\n", "path": "rasterio/features.py"}]}