def update_multiarray_shape_range(spec, feature_name, shape_range):
    """
    Annotate an input or output MLMultiArray feature in a neural network spec
    to accommodate a range of shapes.

    :param spec: MLModel
        The MLModel spec containing the feature.

    :param feature_name: str
        The name of the feature for which to add shape range
        information. If the feature is not found in the input or output
        descriptions then an exception is thrown.

    :param shape_range: NeuralNetworkMultiArrayShapeRange
        A NeuralNetworkMultiArrayShapeRange object with the populated shape
        range information. The shape_range object must either contain only
        shape information for channel or channel, height and width. If
        the object is invalid then an exception is thrown.

    Examples
    --------
    .. sourcecode:: python

        import coremltools
        from coremltools.models.neural_network import flexible_shape_utils

        spec = coremltools.utils.load_spec("mymodel.mlmodel")
        shape_range = flexible_shape_utils.NeuralNetworkMultiArrayShapeRange()
        shape_range.add_channel_range((1, 3))
        shape_range.add_width_range((128, 256))
        shape_range.add_height_range((128, 256))
        flexible_shape_utils.update_multiarray_shape_range(
            spec, feature_name="my_multiarray_featurename", shape_range=shape_range
        )

    :return:
        None. The spec is updated.
    """
    if not isinstance(shape_range, NeuralNetworkMultiArrayShapeRange):
        raise Exception("Shape range should be of type MultiArrayShapeRange")

    shape_range.validate_array_shape_range()
    feature = _get_feature(spec, feature_name)

    if feature.type.WhichOneof("Type") != "multiArrayType":
        raise Exception(
            "Trying to update shape range for " "a non-multiArray feature type"
        )

    # Add channel range
    feature.type.multiArrayType.ClearField("ShapeFlexibility")
    s = feature.type.multiArrayType.shapeRange.sizeRanges.add()
    s.lowerBound = shape_range.get_channel_range().lowerBound
    s.upperBound = shape_range.get_channel_range().upperBound

    if shape_range.get_shape_range_dims() > 1:
        # Add height range
        s = feature.type.multiArrayType.shapeRange.sizeRanges.add()
        s.lowerBound = shape_range.get_height_range().lowerBound
        s.upperBound = shape_range.get_height_range().upperBound
        # Add width range
        s = feature.type.multiArrayType.shapeRange.sizeRanges.add()
        s.lowerBound = shape_range.get_width_range().lowerBound
        s.upperBound = shape_range.get_width_range().upperBound

    # Bump up specification version
    spec.specificationVersion = max(
        _MINIMUM_FLEXIBLE_SHAPES_SPEC_VERSION, spec.specificationVersion
    )

    Annotate an input or output MLMultiArray feature in a neural network spec
    to accommodate a range of shapes.

    :param spec: MLModel
        The MLModel spec containing the feature.

    :param feature_name: str
        The name of the feature for which to add shape range
        information. If the feature is not found in the input or output
        descriptions then an exception is thrown.

    :param shape_range: NeuralNetworkMultiArrayShapeRange
        A NeuralNetworkMultiArrayShapeRange object with the populated shape
        range information. The shape_range object must either contain only
        shape information for channel or channel, height and width. If
        the object is invalid then an exception is thrown.

    Examples
    --------
    .. sourcecode:: python

        import coremltools
        from coremltools.models.neural_network import flexible_shape_utils

        spec = coremltools.utils.load_spec("mymodel.mlmodel")
        shape_range = flexible_shape_utils.NeuralNetworkMultiArrayShapeRange()
        shape_range.add_channel_range((1, 3))
        shape_range.add_width_range((128, 256))
        shape_range.add_height_range((128, 256))
        flexible_shape_utils.update_multiarray_shape_range(
            spec, feature_name="my_multiarray_featurename", shape_range=shape_range
        )

    :return:
        None. The spec is updated.
    
coremltools/models/neural_network/flexible_shape_utils.py