Exemple #1
0
def format_pint_violation(rule, source_value):
    """
    Format a pint min, max violation for human readability.

    :param rule
    :param source_value : Quantity - value to format into range
    :return (formatted_value, formatted_min, formatted_max) : (String, String, String)
    """

    formatted_min = formatted_max = None
    incoming_data_units = source_value.units
    rule_units = ureg(rule.units)
    if rule_units.dimensionless:
        rule_value = source_value
    else:
        rule_value = source_value.to(rule_units)

    pretty_source_units = pretty_units(source_value)
    pretty_rule_units = pretty_units(rule_value)

    if incoming_data_units != rule_units:
        formatted_value = '{:.1f} {} → {:.1f} {}'.format(
            source_value.magnitude, pretty_source_units,
            rule_value.magnitude, pretty_rule_units,
        )
    else:
        formatted_value = '{:.1f} {}'.format(source_value.magnitude, pretty_rule_units)
    if rule.min is not None:
        formatted_min = '{:.1f} {}'.format(rule.min, pretty_rule_units)
    if rule.max is not None:
        formatted_max = '{:.1f} {}'.format(rule.max, pretty_rule_units)
    return (formatted_value, formatted_min, formatted_max)
Exemple #2
0
    def minimum_valid(self, value):
        """
        Validate that the value is not less than the minimum specified by the rule.

        :param value: Value to validate rule against
        :return: bool, True is valid, False if the value is out of range
        """
        # Convert the rule into the correct types for checking the data
        rule_min = self.min
        if rule_min is None:
            return True
        else:
            if isinstance(value, datetime):
                value = value.astimezone(get_current_timezone()).replace(tzinfo=pytz.UTC)
                rule_min = make_aware(datetime.strptime(str(int(rule_min)), '%Y%m%d'), pytz.UTC)
            elif isinstance(value, date):
                value = value
                rule_min = datetime.strptime(str(int(rule_min)), '%Y%m%d').date()
            elif isinstance(value, int):
                rule_min = int(rule_min)
            elif isinstance(value, ureg.Quantity):
                rule_min = rule_min * ureg(self.units)
            elif not isinstance(value, (str, unicode)):
                # must be a float...
                value = float(value)

            try:
                if value < rule_min:
                    return False
                else:
                    # If rule_min is undefined/None or value is okay, then it is valid.
                    return True
            except ValueError:
                raise ComparisonError("Value could not be compared numerically")
Exemple #3
0
    def maximum_valid(self, value):
        """
        Validate that the value is not greater than the maximum specified by the rule.

        :param value: Value to validate rule against
        :return: bool, True is valid, False if the value is out of range
        """
        # Convert the rule into the correct types for checking the data
        rule_max = self.max
        if rule_max is None:
            return True
        else:
            if isinstance(value, datetime):
                value = value.astimezone(get_current_timezone()).replace(tzinfo=pytz.UTC)
                rule_max = make_aware(datetime.strptime(str(int(rule_max)), '%Y%m%d'), pytz.UTC)
            elif isinstance(value, date):
                value = value
                rule_max = datetime.strptime(str(int(rule_max)), '%Y%m%d').date()
            elif isinstance(value, int):
                rule_max = int(rule_max)
            elif isinstance(value, ureg.Quantity):
                rule_max = rule_max * ureg(self.units)
            elif not isinstance(value, basestring):
                # must be a float...
                value = float(value)

            try:
                if value > rule_max:
                    return False
                else:
                    return True
            except ValueError:
                raise ComparisonError("Value could not be compared numerically")
Exemple #4
0
    def to_internal_value(self, data):
        # get the field off of the database table to get the base units
        field = self.root.Meta.model._meta.get_field(self.field_name)

        try:
            data = float(data) * ureg(field.base_units)
        except ValueError:
            data = None

        return data
Exemple #5
0
    def to_internal_value(self, data):
        # get the field off of the database table to get the base units
        field = self.root.Meta.model._meta.get_field(self.field_name)

        try:
            org = self.root.instance.organization

            if field.base_units == 'kBtu/ft**2/year':
                data = float(data) * ureg(org.display_units_eui)
            elif field.base_units == 'ft**2':
                data = float(data) * ureg(org.display_units_area)
            else:
                # This shouldn't happen unless we're supporting a new pints_unit QuantityField.
                data = float(data) * ureg(field.base_units)
        except AttributeError:
            data = float(data) * ureg(field.base_units)
        except ValueError:
            data = None

        return data
Exemple #6
0
def pint_cleaner(value, units, *args):
    """Try to convert value to a meaningful (magnitude, units) object."""
    value = float_cleaner(value)
    # API breakage if None does not return None
    if value is None:
        return None

    try:
        value = value * ureg(units)
    except ValueError:
        value = None
    except TypeError:
        message = 'pint_cleaner cannot convert {} to a valid Quantity'.format(type(value))
        raise TypeError(message)

    return value
Exemple #7
0
def format_pint_violation(rule, source_value):
    """
    Format a pint min, max violation for human readability.

    :param rule
    :param source_value : Quantity - value to format into range
    :return (formatted_value, formatted_min, formatted_max) : (String, String, String)
    """
    def pretty_units(q):
        """
        hack; can lose it when Pint gets something like a "{:~U}" format code
        see https://github.com/hgrecco/pint/pull/231
        """
        return u"{:~P}".format(q).split(" ")[1]

    formatted_min = formatted_max = None
    incoming_data_units = source_value.units
    rule_units = ureg(rule.units)
    rule_value = source_value.to(rule_units)

    pretty_source_units = pretty_units(source_value)
    pretty_rule_units = pretty_units(rule_value)

    if incoming_data_units != rule_units:
        formatted_value = u"{:.1f} {} → {:.1f} {}".format(
            source_value.magnitude,
            pretty_source_units,
            rule_value.magnitude,
            pretty_rule_units,
        )
    else:
        formatted_value = u"{:.1f} {}".format(source_value, pretty_rule_units)
    if rule.min is not None:
        formatted_min = u"{:.1f} {}".format(rule.min, pretty_rule_units)
    if rule.max is not None:
        formatted_max = u"{:.1f} {}".format(rule.max, pretty_rule_units)
    return (formatted_value, formatted_min, formatted_max)
Exemple #8
0
    def test_mapping_takes_into_account_selected_units(self):
        # Just as in the previous test, build extra_data PropertyState
        raw_state = self.property_state_factory.get_property_state_as_extra_data(
            import_file_id=self.import_file.id,
            source_type=ASSESSED_RAW,
            data_state=DATA_STATE_IMPORT,
        )

        # Replace the site_eui and gross_floor_area key-value that gets
        # autogenerated by get_property_state_as_extra_data
        del raw_state.extra_data['site_eui']
        raw_state.extra_data['Site EUI'] = 100

        del raw_state.extra_data['gross_floor_area']
        raw_state.extra_data['Gross Floor Area'] = 100
        raw_state.save()

        self.import_file.raw_save_done = True
        self.import_file.save()

        # Build mappings - with unit-aware destinations and non-default unit choices
        suggested_mappings = mapper.build_column_mapping(
            list(raw_state.extra_data.keys()),
            Column.retrieve_all_by_tuple(self.org),
            previous_mapping=get_column_mapping,
            map_args=[self.org],
            thresh=80)

        mappings = []
        for raw_column, suggestion in suggested_mappings.items():
            if raw_column == 'Site EUI':
                mappings.append({
                    "from_field": raw_column,
                    "from_units": 'kWh/m**2/year',
                    "to_table_name": 'PropertyState',
                    "to_field": 'site_eui',
                    "to_field_display_name": 'Site EUI',
                })
            elif raw_column == 'Gross Floor Area':
                mappings.append({
                    "from_field": raw_column,
                    "from_units": 'm**2',
                    "to_table_name": 'PropertyState',
                    "to_field": 'gross_floor_area',
                    "to_field_display_name": 'Gross Floor Area',
                })
            else:
                other_mapping = {
                    "from_field": raw_column,
                    "from_units": None,
                    "to_table_name": suggestion[0],
                    "to_field": suggestion[1],
                    "to_field_display_name": suggestion[1],
                }
                mappings.append(other_mapping)

        # Perform mapping, creating the initial PropertyState records.
        Column.create_mappings(mappings, self.org, self.user,
                               self.import_file.id)
        tasks.map_data(self.import_file.id)

        # Verify that the values have been converted appropriately
        state = self.import_file.find_unmatched_property_states().get()

        self.assertAlmostEqual(state.site_eui,
                               (100 *
                                ureg('kWh/m**2/year')).to('kBtu/ft**2/year'))
        self.assertAlmostEqual(state.gross_floor_area,
                               (100 * ureg('m**2')).to('ft**2'))
Exemple #9
0
def pretty_units_from_spec(unit_spec):
    quantity = 0 * ureg(unit_spec)  # doesn't matter what the number is
    return pretty_units(quantity)