Repository: rasterio/rasterio

Issue:
rasterize should take an enum for merge_alg
At https://github.com/mapbox/rasterio/blob/master/rasterio/features.py#L165

in the same way that `reproject()` takes `resampling=Resampling.nearest`.


Discussion:

Resolving patch:
diff --git a/rasterio/features.py b/rasterio/features.py
--- a/rasterio/features.py
+++ b/rasterio/features.py
@@ -2,12 +2,14 @@
 
 
 import logging
-
+import warnings
 import numpy as np
 
 from rasterio._features import _shapes, _sieve, _rasterize, _bounds
 from rasterio.dtypes import validate_dtype, can_cast_dtype, get_minimum_dtype
+from rasterio.enums import MergeAlg
 from rasterio.env import ensure_env
+from rasterio.errors import RasterioDeprecationWarning
 from rasterio.transform import IDENTITY, guard_transform
 from rasterio.windows import Window
 
@@ -153,7 +155,7 @@ def rasterize(
         out=None,
         transform=IDENTITY,
         all_touched=False,
-        merge_alg='replace',
+        merge_alg=MergeAlg.replace,
         default_value=1,
         dtype=None):
     """Return an image array with input geometries burned in.
@@ -180,8 +182,10 @@ def rasterize(
         false, only pixels whose center is within the polygon or that
         are selected by Bresenham's line algorithm will be burned in.
     merge_alg : str, optional
-        If `replace` (default), the new value will overwrite the existing value.
-        If `add`, the new value will be added to the existing raster.
+        Merge algorithm to use.  One of:
+            MergeAlg.replace (default): the new value will overwrite the
+                existing value.
+            MergeAlg.add: the new value will be added to the existing raster.
     default_value : int or float, optional
         Used as value for all geometries, if not provided in `shapes`.
     dtype : rasterio or numpy data type, optional
@@ -200,6 +204,14 @@ def rasterize(
     rasterio.float64.
 
     """
+
+    # merge_alg usage deprecation warning.  Can be removed in rasterio 1.0
+    if not isinstance(merge_alg, MergeAlg):
+        warnings.warn("merge_alg must be MergeAlg.add or MergeAlg.replace, "
+                      "not a 'replace' or 'add'.  This usage has been "
+                      "deprecated.", RasterioDeprecationWarning)
+        merge_alg = MergeAlg[merge_alg]
+
     valid_dtypes = (
         'int16', 'int32', 'uint8', 'uint16', 'uint32', 'float32', 'float64'
     )


Test patch:
diff --git a/tests/test_features.py b/tests/test_features.py
--- a/tests/test_features.py
+++ b/tests/test_features.py
@@ -7,7 +7,8 @@
 from affine import Affine
 
 import rasterio
-from rasterio.errors import WindowError
+from rasterio.enums import MergeAlg
+from rasterio.errors import WindowError, RasterioDeprecationWarning
 from rasterio.features import (
     bounds, geometry_mask, geometry_window, is_valid_geom, rasterize, sieve,
     shapes)
@@ -547,7 +548,7 @@ def test_rasterize_all_touched(basic_geometry, basic_image):
         )
     )
 
-def test_rasterize_merge_alg(basic_geometry, basic_image_2x2x2):
+def test_rasterize_merge_alg_add(basic_geometry, basic_image_2x2x2):
     """
     Rasterizing two times the basic_geometry with the "add" merging
     option should output the shape with the value 2
@@ -556,11 +557,23 @@ def test_rasterize_merge_alg(basic_geometry, basic_image_2x2x2):
         assert np.array_equal(
             basic_image_2x2x2,
             rasterize(
-                [basic_geometry, basic_geometry], merge_alg='add',
+                [basic_geometry, basic_geometry], merge_alg=MergeAlg.add,
                 out_shape=DEFAULT_SHAPE)
         )
 
 
+def test_rasterize_merge_alg_deprecated(basic_geometry, basic_image_2x2x2):
+    """
+    Rasterizing two times the basic_geometry with the "add" merging
+    option should output the shape with the value 2
+    """
+    for alg in ('add', 'replace'):
+        with pytest.warns(RasterioDeprecationWarning):
+            with rasterio.Env():
+                rasterize([basic_geometry, basic_geometry], merge_alg=alg,
+                          out_shape=DEFAULT_SHAPE)
+
+
 def test_rasterize_value(basic_geometry, basic_image_2x2):
     """
     All shapes should rasterize to the value passed in a tuple alongside