Esempio n. 1
0
    def __init__(self, amount, unit=None, unit_numer=(), unit_denom=()):
        if isinstance(amount, Number):
            assert not unit and not unit_numer and not unit_denom
            self.value = amount.value
            self.unit_numer = amount.unit_numer
            self.unit_denom = amount.unit_denom
            return

        if not isinstance(amount, (int, float)):
            raise TypeError("Expected number, got %r" % (amount,))

        if unit is not None:
            unit_numer = unit_numer + (unit.lower(),)

        # Cancel out any convertable units on the top and bottom
        numerator_base_units = count_base_units(unit_numer)
        denominator_base_units = count_base_units(unit_denom)

        # Count which base units appear both on top and bottom
        cancelable_base_units = {}
        for unit, count in numerator_base_units.items():
            cancelable_base_units[unit] = min(
                count, denominator_base_units.get(unit, 0))

        # Actually remove the units
        numer_factor, unit_numer = cancel_base_units(unit_numer, cancelable_base_units)
        denom_factor, unit_denom = cancel_base_units(unit_denom, cancelable_base_units)

        # And we're done
        self.unit_numer = tuple(unit_numer)
        self.unit_denom = tuple(unit_denom)
        self.value = amount * (numer_factor / denom_factor)
Esempio n. 2
0
    def __init__(self, amount, unit=None, unit_numer=(), unit_denom=()):
        if isinstance(amount, Number):
            assert not unit and not unit_numer and not unit_denom
            self.value = amount.value
            self.unit_numer = amount.unit_numer
            self.unit_denom = amount.unit_denom
            return

        if not isinstance(amount, (int, float)):
            raise TypeError("Expected number, got %r" % (amount, ))

        if unit is not None:
            unit_numer = unit_numer + (unit.lower(), )

        # Cancel out any convertable units on the top and bottom
        numerator_base_units = count_base_units(unit_numer)
        denominator_base_units = count_base_units(unit_denom)

        # Count which base units appear both on top and bottom
        cancelable_base_units = {}
        for unit, count in numerator_base_units.items():
            cancelable_base_units[unit] = min(
                count, denominator_base_units.get(unit, 0))

        # Actually remove the units
        numer_factor, unit_numer = cancel_base_units(unit_numer,
                                                     cancelable_base_units)
        denom_factor, unit_denom = cancel_base_units(unit_denom,
                                                     cancelable_base_units)

        # And we're done
        self.unit_numer = tuple(unit_numer)
        self.unit_denom = tuple(unit_denom)
        self.value = amount * (numer_factor / denom_factor)
Esempio n. 3
0
    def __init__(self, amount, unit=None, unit_numer=(), unit_denom=()):
        if isinstance(amount, Number):
            assert not unit and not unit_numer and not unit_denom
            self.value = amount.value
            self.unit_numer = amount.unit_numer
            self.unit_denom = amount.unit_denom
            return

        # Numbers with units are stored internally as a "base" unit, which can
        # involve float division, which can lead to precision errors in obscure
        # cases.  Storing the original units would only partially solve this
        # problem, because there'd still be a possible loss of precision when
        # converting in Sass-land.  Almost all of the conversion factors are
        # simple ratios of small whole numbers, so using Fraction across the
        # board preserves as much precision as possible.
        # TODO in fact, i wouldn't mind parsing Sass values as fractions of a
        # power of ten!
        # TODO this slowed the test suite down by about 10%, ha
        if isinstance(amount, (int, float)):
            amount = Fraction.from_float(amount)
        elif isinstance(amount, Fraction):
            pass
        else:
            raise TypeError("Expected number, got %r" % (amount, ))

        if unit is not None:
            unit_numer = unit_numer + (unit.lower(), )

        # Cancel out any convertable units on the top and bottom
        numerator_base_units = count_base_units(unit_numer)
        denominator_base_units = count_base_units(unit_denom)

        # Count which base units appear both on top and bottom
        cancelable_base_units = {}
        for unit, count in numerator_base_units.items():
            cancelable_base_units[unit] = min(
                count, denominator_base_units.get(unit, 0))

        # Actually remove the units
        numer_factor, unit_numer = cancel_base_units(unit_numer,
                                                     cancelable_base_units)
        denom_factor, unit_denom = cancel_base_units(unit_denom,
                                                     cancelable_base_units)

        # And we're done
        self.unit_numer = tuple(unit_numer)
        self.unit_denom = tuple(unit_denom)
        self.value = amount * (numer_factor / denom_factor)
Esempio n. 4
0
    def __init__(self, amount, unit=None, unit_numer=(), unit_denom=()):
        if isinstance(amount, Number):
            assert not unit and not unit_numer and not unit_denom
            self.value = amount.value
            self.unit_numer = amount.unit_numer
            self.unit_denom = amount.unit_denom
            return

        # Numbers with units are stored internally as a "base" unit, which can
        # involve float division, which can lead to precision errors in obscure
        # cases.  Storing the original units would only partially solve this
        # problem, because there'd still be a possible loss of precision when
        # converting in Sass-land.  Almost all of the conversion factors are
        # simple ratios of small whole numbers, so using Fraction across the
        # board preserves as much precision as possible.
        # TODO in fact, i wouldn't mind parsing Sass values as fractions of a
        # power of ten!
        # TODO this slowed the test suite down by about 10%, ha
        if isinstance(amount, (int, float)):
            amount = Fraction.from_float(amount)
        elif isinstance(amount, Fraction):
            pass
        else:
            raise TypeError("Expected number, got %r" % (amount,))

        if unit is not None:
            unit_numer = unit_numer + (unit.lower(),)

        # Cancel out any convertable units on the top and bottom
        numerator_base_units = count_base_units(unit_numer)
        denominator_base_units = count_base_units(unit_denom)

        # Count which base units appear both on top and bottom
        cancelable_base_units = {}
        for unit, count in numerator_base_units.items():
            cancelable_base_units[unit] = min(
                count, denominator_base_units.get(unit, 0))

        # Actually remove the units
        numer_factor, unit_numer = cancel_base_units(unit_numer, cancelable_base_units)
        denom_factor, unit_denom = cancel_base_units(unit_denom, cancelable_base_units)

        # And we're done
        self.unit_numer = tuple(unit_numer)
        self.unit_denom = tuple(unit_denom)
        self.value = amount * (numer_factor / denom_factor)