def diff_model()

in apichanges/model.py [0:0]


def diff_model(new, old=None):
    new = ServiceModel(new)
    log.debug("delta diffing service:%s", new.service_name)
    if old:
        old = ServiceModel(old)
        new_methods = set(new.operation_names).difference(old.operation_names)
    else:
        new_methods = set(new.operation_names)

    changes = []
    for n in new_methods:
        changes.append(NewMethod(new, n))

    if not old:
        return ServiceChange(new, changes, new=True)

    old_shapes = set(old.shape_names)
    modified_shapes = []

    # TODO: with a shape cache for equality/delta we could avoid
    # extraneous compares on shape recursion.
    for s in new.shape_names:
        ns = new.shape_for(s)
        if s not in old_shapes:
            continue
        os = old.shape_for(s)
        if ns == os:  # equality visitor
            continue
        delta = ns.delta(os)
        if delta:
            modified_shapes.append((s, delta))

    mshape_map = dict(modified_shapes)
    for op in new.operation_names:
        op_delta = {}
        op_shape = new.operation_model(op)
        if op_shape.input_shape and op_shape.input_shape.name in mshape_map:
            op_delta["request"] = d_i = mshape_map[op_shape.input_shape.name]
        if op_shape.output_shape and op_shape.output_shape.name in mshape_map:
            op_delta["response"] = mshape_map[op_shape.output_shape.name]

        # sigh ec2 service specific hack
        if (
            new.service_name == "ec2"
            and "request" in op_delta
            and "TagSpecifications" in d_i
        ):
            d_i.pop("TagSpecifications")
            if not d_i:
                op_delta.pop("request")
        if not op_delta:
            continue
        if len(op_delta) == 2 and op_delta["request"] == op_delta["response"]:
            op_delta = {"both": op_delta["request"]}
        changes.append(UpdatedMethod(new.service_name, op, op_delta))

    if changes:
        return ServiceChange(new, changes)