예제 #1
0
 def test_conflicting_roles(self):
     with raises(ValueError):
         CustomUnitPolicy([
             ScaleUnitConversion(Unit('m'), Unit('km'), 0.001),
             ScaleUnitConversion(Unit('km'), Unit('mm'), 1000000)
         ],
                          duplicates='overwrite')
예제 #2
0
 def test_duplicate_raise(self):
     with raises(ValueError):
         CustomUnitPolicy([
             ScaleUnitConversion(Unit('km'), Unit('m'), 1000),
             ScaleUnitConversion(Unit('km'), Unit('mm'), 1000000)
         ],
                          duplicates='raise')
예제 #3
0
 def test_alias(self, custom_unit_conversion):
     alias = custom_unit_conversion.alias(Unit('jiggyjag'))
     assert alias == CustomUnitConversion(Unit('jiggyjag'), Unit('bork'),
                                          lambda x: x**2,
                                          lambda x: math.sqrt(x))
     assert alias.to_ref(12) == approx(144)
     assert alias.from_ref(9) == approx(3)
예제 #4
0
 def test_convert_to_ref(self):
     cup = CustomUnitPolicy([
         ScaleUnitConversion(Unit('km'), Unit('m'), 1000),
         ScaleUnitConversion(Unit('mm'), Unit('m'), 0.001),
         AffineUnitConversion(Unit('C'), Unit('K'), 1, 273.15)
     ])
     assert cup.convert_to_ref(42, Unit('km')) == 42000  # source to ref
     assert cup.convert_to_ref(42, Unit('m')) == 42  # ref to ref
     with raises(ValueError):
         cup.convert_to_ref(42, Unit('bogus'))  # unit doesn't exist
예제 #5
0
 def test_eq(self):
     assert IdentityUnitConversion(Unit('metre'),
                                   Unit('m')) == IdentityUnitConversion(
                                       Unit('metre'), Unit('m'))
     assert IdentityUnitConversion(Unit('metre'),
                                   Unit('m')) != IdentityUnitConversion(
                                       Unit('mtr'), Unit('m'))
예제 #6
0
 def test_eq(self):
     assert ScaleUnitConversion(Unit('mm'), Unit('m'),
                                0.001) == ScaleUnitConversion(
                                    Unit('mm'), Unit('m'), 0.001)
     assert ScaleUnitConversion(Unit('bs'), Unit('m'),
                                0.123) != ScaleUnitConversion(
                                    Unit('mm'), Unit('m'), 0.001)
 def test_evaluate_expression_syntax_error(self):
     df = pd.DataFrame(data=[[nan, 'gnu', 3], [4, 'gnat', '{{((((*+-/ x y heres_a_syntax_error!!!!!!!!!!!!!!!!}}']],
                       columns=['a', 'b', 'c'])
     col_specs = {n: ColumnMetadata(Unit(u)) for n, u in zip(['a', 'b', 'c'], ['-', 'text', 'm'])}
     t = Table(df=df, name='some_table', col_specs=col_specs, destinations=['success', 'glory'])
     with raises(SyntaxError, match=r"Syntax error in expression in table 'some_table', column 2, row 1"):
         t.evaluate_expressions({'x': 7, 'y': 9}, inplace=False)
예제 #8
0
    def __init__(self,
                 df: pd.DataFrame,
                 name: str,
                 col_specs: Dict[str, ColumnMetadata] = None,
                 destinations: Optional[Iterable[str]] = None,
                 origin: Optional[TableOrigin] = None,
                 remark: Optional[str] = None):
        """

        :param df: DataFrame of Table contents.
        :param name: Name of this Table.
        :param col_specs: If supplied, specifies column metadata. If not, these are created with default values.
        :param destinations: Iterable of destination strings.
        :param origin:
        :param remark: Free-text remark about this table block.
        """

        if col_specs:
            self._validate_col_specs(col_specs, df.columns)
            df: pd.DataFrame = df.copy()
            self._col_specs = col_specs
        else:
            self._col_specs = {
                col_name: ColumnMetadata(Unit(DEFAULT_UNIT_STR))
                for col_name in df.columns
            }

        self.name = name
        if not destinations:
            destinations = [DEFAULT_DESTINATION]
        self._destinations = self._sanitize_destinations(destinations)
        self.origin = origin

        self._df = df
        self.remark = remark
예제 #9
0
 def test_iter(self):
     cup = CustomUnitPolicy([
         ScaleUnitConversion(Unit('km'), Unit('m'), 1000),
         ScaleUnitConversion(Unit('mm'), Unit('m'), 0.001),
         AffineUnitConversion(Unit('C'), Unit('K'), 1, 273.15)
     ])
     assert Unit('mm') in cup
     assert Unit('m') in cup
     assert set(cup) == {'km', 'mm', 'm', 'C', 'K'}
예제 #10
0
 def test_ref_unit(self):
     cup = CustomUnitPolicy(
         [ScaleUnitConversion(Unit('km'), Unit('m'), 1000)])
     assert cup.ref_unit(Unit('km')) == Unit('m')
     assert cup.ref_unit(Unit('m')) == Unit('m')
     with raises(ValueError):
         cup.ref_unit(Unit('furlong'))  # unit doesn't exist
예제 #11
0
 def test_convert_to_home_units(self):
     df = pd.DataFrame([
         [11, 12, 13],
         [21, 22, 23]], columns=['a', 'b', 'c'])
     cs = {n: ColumnMetadata(Unit(u), Unit(hu)) for n, u, hu in zip(
         ['a', 'b', 'c'], ['m', 'm', 'm'], ['m', 'mm', 'km'])}
     t = Table(df, name='Fool', col_specs=cs)
     cup = CustomUnitPolicy([
         ScaleUnitConversion(Unit('mm'), Unit('m'), 0.001),
         ScaleUnitConversion(Unit('km'), Unit('m'), 1000)])
     t_home = t.convert_to_home_units(cup)
     assert t_home.col_units == [Unit('m'), Unit('mm'), Unit('km')]
     assert (np.array(t_home.df) == np.array([[11, 12000, 0.013],
                                              [21, 22000, 0.023]])).all()
예제 #12
0
 def test_duplicate_overwrite(self):
     cup = CustomUnitPolicy([
         ScaleUnitConversion(Unit('km'), Unit('m'), 1000),
         ScaleUnitConversion(Unit('km'), Unit('mm'), 1000000)
     ],
                            duplicates='overwrite')
     assert cup.ref_unit(Unit('km')) == Unit('mm')
예제 #13
0
    def convert_units(self,
                      unit_policy: UnitPolicy,
                      new_units: Dict[str, Unit] = None,
                      inplace: bool = False,
                      new_unit_missing: str = 'raise') -> Optional['Table']:
        """
        Changes values and units in accordance with unit policy.
        :param unit_policy: Unit policy that will govern unit conversion.
        :param new_units: dict of column name --> new unit. If none, unit_policy decides.
        :param inplace: If True, convert values and unit fields in-place. If False, return a new converted Table.
        :param new_unit_missing: {'ignore', 'raise'}, default 'raise'. Defines behaviour if a column's new unit is not supported
        by the unit policy. If 'raise', raise an exception. If 'ignore', leave the unit in place, no conversion done.
        # TODO what about if old unit is not in policy...
        """

        new_unit_missing_options = {'ignore', 'raise'}
        if new_unit_missing not in new_unit_missing_options:
            raise ValueError(
                f"Expected one of {new_unit_missing_options}, got '{new_unit_missing}'."
            )

        table = self if inplace else self.copy()

        for col in table.df:
            old_unit = self._col_specs[col].unit
            if old_unit != Unit(TEXT_COL_UNIT_STR):
                try:
                    new_unit = new_units[col]
                except KeyError:
                    if new_unit_missing == 'raise':
                        raise ValueError(
                            f"New unit missing for column '{col}'.")
                    continue  # Move on to next column.
                try:
                    # Convert values in this col
                    table.df[col] = table.df[col].apply(unit_policy.convert,
                                                        from_unit=old_unit,
                                                        to_unit=new_unit)
                    # Change this col's unit to ref_unit
                    table._col_specs[col].unit = new_unit
                except ValueError as ve:
                    raise ValueError(
                        f"Can't convert unit of column '{col}' from '{old_unit}' to '{new_unit}'."
                    ) from ve

        if not inplace:
            return table
예제 #14
0
 def test_convert_to_ref_units(self):
     df = pd.DataFrame([
         [11, 12, 13],
         [21, 22, 23]], columns=['a', 'b', 'c'])
     cs = {n: ColumnMetadata(Unit(u)) for n, u in zip(['a', 'b', 'c'], ['m', 'mm', 'km'])}
     t = Table(df, name='Fool', col_specs=cs)
     cup = CustomUnitPolicy([
         ScaleUnitConversion(Unit('mm'), Unit('m'), 0.001),
         ScaleUnitConversion(Unit('km'), Unit('m'), 1000)])
     t_ref = t.convert_to_ref_units(cup, inplace=False)
     assert t_ref.col_units == [Unit('m')] * 3
     assert (np.array(t_ref.df) == np.array([[11, 0.012, 13000],
                                             [21, 0.022, 23000]])).all()
예제 #15
0
 def test_to_csv_nonstring_colnames_and_destinations(self):
     # PS-53 Bundle.to_csv() fails when column names are not strings
     nonstring_colnames = [1.234, 666.0, 42.0]
     nonstring_destinations = [1984, 2001.2001]
     df = pd.DataFrame(data=[[nan, 'gnu', 3], [4, 'gnat', '{{(+ x y)}}']], columns=nonstring_colnames)
     col_specs = {n: ColumnMetadata(Unit(u)) for n, u in zip(nonstring_colnames, ['-', 'text', 'm'])}
     t = Table(df=df, name='some_table', col_specs=col_specs,
               destinations=nonstring_destinations)
     out = io.StringIO()
     t.to_csv(out)
     assert out.getvalue() == dedent("""\
         **some_table;;
         1984 2001.2001
         1.234;666.0;42.0
         -;text;m
         -;gnu;3
         4.0;gnat;{{(+ x y)}}
         
         """)
예제 #16
0
    def test_convert_to_ref_units_unknown_unit(self):
        df = pd.DataFrame([
            [11, 12, 13],
            [21, 22, 23]], columns=['a', 'b', 'c'])
        cs = {n: ColumnMetadata(Unit(u)) for n, u in zip(['a', 'b', 'c'], ['m', 'mm', 'km'])}
        t = Table(df, name='Fool', col_specs=cs)
        cup_no_km = CustomUnitPolicy([ScaleUnitConversion(Unit('mm'), Unit('m'), 0.001)])
        t_ref_no_km = t.convert_to_ref_units(cup_no_km, inplace=False, units_not_in_policy='ignore')
        assert t_ref_no_km.col_units == [Unit('m'), Unit('m'), Unit('km')]
        assert (np.array(t_ref_no_km.df) == np.array([[11, 0.012, 13],
                                                      [21, 0.022, 23]])).all()

        with raises(ValueError):
            t.convert_to_ref_units(cup_no_km, inplace=False, units_not_in_policy='raise')
예제 #17
0
    def convert_to_ref_units(
            self,
            unit_policy: UnitPolicy,
            inplace: bool = False,
            units_not_in_policy: str = 'raise') -> Optional['Table']:
        """
        Converts values and units to unit policy's reference units.
        :param unit_policy:
        :param inplace:
        :param units_not_in_policy: {'ignore', 'raise'}, default 'raise'. Defines behaviour if a column's unit is not supported by
        the unit policy. If 'raise', raise an exception. If 'ignore', leave the unit in place, no conversion done.
        """
        # TODO unit conversion will fail on expressions

        units_not_in_policy_options = {'ignore', 'raise'}
        if units_not_in_policy not in units_not_in_policy_options:
            raise ValueError(
                f"Expected one of {units_not_in_policy_options}, got '{units_not_in_policy}'."
            )

        table = self if inplace else self.copy()

        for col in table.df:
            old_unit = self._col_specs[col].unit
            if not old_unit == Unit(TEXT_COL_UNIT_STR):
                try:
                    # Convert values in this col
                    table.df[col] = table.df[col].apply(
                        unit_policy.convert_to_ref, src_unit=old_unit)
                    # Change this col's unit to ref_unit
                    table._col_specs[col].unit = unit_policy.ref_unit(old_unit)
                except ValueError:
                    if units_not_in_policy == 'raise':
                        raise ValueError(
                            f"Unit '{old_unit}' of column '{col}' not found in unit policy."
                        )
                    pass  # Ignore the unknown unit, do no conversion

        if not inplace:
            return table
예제 #18
0
 def test_reverse(self, custom_unit_conversion):
     assert custom_unit_conversion.reverse() == \
            CustomUnitConversion(Unit('bork'), Unit('zonk'), lambda x: math.sqrt(x), lambda x: x ** 2)
예제 #19
0
 def test_alias(self):
     alias = ScaleUnitConversion(Unit('mm'), Unit('m'),
                                 0.001).alias(Unit('millimetre'))
     assert alias == ScaleUnitConversion(Unit('millimetre'), Unit('m'),
                                         0.001)
     assert alias.to_ref(1000) == 1
예제 #20
0
 def test_eq(self, custom_unit_conversion):
     assert custom_unit_conversion == \
            CustomUnitConversion(Unit('zonk'), Unit('bork'), lambda x: x ** 2, lambda x: math.sqrt(x))
     assert custom_unit_conversion != \
            CustomUnitConversion(Unit('zonk'), Unit('bork'), lambda x: x ** 2, lambda x: x)
예제 #21
0
 def custom_unit_conversion(self) -> CustomUnitConversion:
     return CustomUnitConversion(Unit('zonk'), Unit('bork'), lambda x: x**2,
                                 lambda x: math.sqrt(x))
예제 #22
0
 def test_reverse(self):
     assert AffineUnitConversion(
         Unit('degC'), Unit('K'), 1,
         273.15).reverse().to_ref(293.15) == approx(20)
예제 #23
0
 def test_from_ref(self):
     assert ScaleUnitConversion(Unit('mm'), Unit('m'),
                                0.001).from_ref(42) == 42000
예제 #24
0
 def col_specs(self):
     return {n: ColumnMetadata(Unit(u)) for n, u in zip(['a', 'b', 'c'], ['-', 'text', 'm'])}
예제 #25
0
 def test_eq(self):
     assert AffineUnitConversion(Unit('degC'), Unit('K'), 1, 273.15) == \
            AffineUnitConversion(Unit('degC'), Unit('K'), 1, 273.15)
     assert AffineUnitConversion(Unit('degC'), Unit('K'), 1, 273.15) != \
            AffineUnitConversion(Unit('degC'), Unit('K'), 1, 666)
예제 #26
0
 def test_to_ref(self):
     assert ScaleUnitConversion(Unit('mm'), Unit('m'),
                                0.001).to_ref(42) == 0.042
예제 #27
0
 def test_to_ref(self):
     assert AffineUnitConversion(Unit('degC'), Unit('K'), 1,
                                 273.15).to_ref(-273.15) == 0
예제 #28
0
 def test_reverse(self):
     assert ScaleUnitConversion(Unit('mm'), Unit('m'),
                                0.001).reverse().to_ref(42) == approx(42000)
예제 #29
0
 def col_specs_with_format(self):
     return {'a': ColumnMetadata(Unit('-'), format_str='${:,.2f}'),
             'b': ColumnMetadata(Unit('text')),
             'c': ColumnMetadata(Unit('m'), format_str='.4e')}
예제 #30
0
 def test_from_ref(self):
     assert AffineUnitConversion(Unit('degC'), Unit('K'), 1,
                                 273.15).from_ref(0) == -273.15