Esempio n. 1
0
def merge_state(merged_state, state1, state2, priorities):
    """
    Set attributes on our Canonical model, saving differences.

    :param merged_state: PropertyState/TaxLotState model inst.
    :param state1: PropertyState/TaxLotState model inst. Left parent.
    :param state2: PropertyState/TaxLotState model inst. Right parent.
    :param priorities: dict, column names with favor new or existing
    :return: inst(``merged_state``), updated.
    """
    # Calculate the difference between the two states and save into a dictionary
    can_attrs = get_state_attrs([state1, state2])

    default = state2
    for attr in can_attrs:
        # Do we have any differences between these fields? - Check if not None instead of if value.
        attr_values = [
            value for value in list(can_attrs[attr].values())
            if value is not None
        ]
        attr_values = [v for v in attr_values if v is not None]

        attr_value = None
        # Two, differing values are set.
        if len(attr_values) > 1:
            # If we have more than one value for this field, choose based on the column priority
            col_prior = priorities.get(attr, 'Favor New')
            if col_prior == 'Favor New':
                attr_value = can_attrs[attr][state2]
            else:  # favor the existing field
                attr_value = can_attrs[attr][state1]

        # No values are set
        elif len(attr_values) < 1:
            attr_value = None

        # There is only one value set.
        else:
            attr_value = attr_values.pop()

        if callable(attr):
            # This callable will be responsible for setting the attribute value, not just returning it.
            attr(merged_state, default)
        else:
            setattr(merged_state, attr, attr_value)

    merged_state.extra_data = _merge_extra_data(state1.extra_data,
                                                state2.extra_data,
                                                priorities['extra_data'])

    # merge measures, scenarios, simulations
    if isinstance(merged_state, PropertyState):
        PropertyState.merge_relationships(merged_state, state1, state2)

    return merged_state
Esempio n. 2
0
def merge_state(merged_state, state1, state2, can_attrs, default=None):
    """
    Set attributes on our Canonical model, saving differences.

    :param merged_state: PropertyState/TaxLotState model inst.
    :param state1: PropertyState/TaxLotState model inst. Left parent.
    :param state2: PropertyState/TaxLotState model inst. Right parent.
    :param can_attrs:  dict of dicts, {'attr_name': {'dataset1': 'value'...}}.
    :param default: (optional), which dataset's value to default to.
    :return: inst(``merged_state``), updated.
    """
    default = default or state2
    changes = []
    for attr in can_attrs:
        # Do we have any differences between these fields? - Check if not None instead of if value.
        attr_values = list(
            set([
                value for value in can_attrs[attr].values()
                if value is not None
            ]))
        attr_values = [v for v in attr_values if v is not None]

        attr_value = None
        # Two, differing values are set.
        if len(attr_values) > 1:
            # If we have more than one value for this field, save each of the field options in the DB,
            # but opt for the default when there is a difference.
            attr_value = can_attrs[attr][default]

        # No values are set
        elif len(attr_values) < 1:
            attr_value = None

        # There is only one value set.
        else:
            attr_value = attr_values.pop()

        if callable(attr):
            # This callable will be responsible for setting the attribute value, not just returning it.
            attr(merged_state, default)
        else:
            setattr(merged_state, attr, attr_value)

    merged_extra_data, merged_extra_data_sources = _merge_extra_data(
        state1, state2, default=default)
    merged_state.extra_data = merged_extra_data

    # merge measures, scenarios, simulations
    if isinstance(merged_state, PropertyState):
        PropertyState.merge_relationships(merged_state, state1, state2)

    return merged_state, changes
Esempio n. 3
0
def merge_state(merged_state, state1, state2, priorities, ignore_merge_protection=False):
    """
    Set attributes on our Canonical model, saving differences.

    :param merged_state: PropertyState/TaxLotState model inst.
    :param state1: PropertyState/TaxLotState model inst. Left parent.
    :param state2: PropertyState/TaxLotState model inst. Right parent.
    :param priorities: dict, column names with favor new or existing
    :return: inst(``merged_state``), updated.
    """
    # Calculate the difference between the two states and save into a dictionary
    can_attrs = get_state_attrs([state1, state2])

    # Handle geocoding results first so that recognize_empty logic is not processed on them.
    _merge_geocoding_results(merged_state, state1, state2, priorities, can_attrs, ignore_merge_protection)

    recognize_empty_columns = state2.organization.column_set.filter(
        table_name=state2.__class__.__name__,
        recognize_empty=True,
        is_extra_data=False
    ).values_list('column_name', flat=True)

    default = state2
    for attr in can_attrs:
        recognize_empty = attr in recognize_empty_columns

        attr_values = [
            value
            for value
            in list(can_attrs[attr].values())
            if value is not None or recognize_empty
        ]

        attr_value = None
        # Two, differing values are set.
        if len(attr_values) > 1:
            # If we have more than one value for this field, choose based on the column priority
            col_prior = priorities.get(attr, 'Favor New')
            if ignore_merge_protection or col_prior == 'Favor New':
                attr_value = can_attrs[attr][state2]
            else:  # favor the existing field
                attr_value = can_attrs[attr][state1]

        # No values are set
        elif len(attr_values) < 1:
            attr_value = None

        # There is only one value set.
        else:
            attr_value = attr_values.pop()

        if callable(attr):
            # This callable will be responsible for setting the attribute value, not just returning it.
            attr(merged_state, default)
        else:
            setattr(merged_state, attr, attr_value)

    recognize_empty_ed_columns = state2.organization.column_set.filter(
        table_name=state2.__class__.__name__,
        recognize_empty=True,
        is_extra_data=True
    ).values_list('column_name', flat=True)

    merged_state.extra_data = _merge_extra_data(
        state1.extra_data,
        state2.extra_data,
        priorities['extra_data'],
        recognize_empty_ed_columns,
        ignore_merge_protection
    )

    # merge measures, scenarios, simulations
    if isinstance(merged_state, PropertyState):
        PropertyState.merge_relationships(merged_state, state1, state2)

    return merged_state