def test_non_fractional(self): self.assertDictEqual( unitconv.parse_unitname('Kimo'), {'multiplier': 1024 * 60 * 60 * 24 * 30, 'unit_class': 'time', 'primary_unit': 's', 'base_unit': 'mo', 'numer_multiplier': 1024 * 60 * 60 * 24 * 30, 'numer_unit_class': 'time', 'numer_primary_unit': 's', 'numer_base_unit': 'mo'})
def test_unparseable(self): self.assertDictEqual( unitconv.parse_unitname('/w'), {'multiplier': 1, 'unit_class': None, 'primary_unit': '/w', 'base_unit': '/w'}) self.assertDictEqual( unitconv.parse_unitname('/'), {'multiplier': 1, 'unit_class': None, 'primary_unit': '/', 'base_unit': '/'}) self.assertDictEqual( unitconv.parse_unitname('a/b/c'), {'multiplier': 1, 'unit_class': None, 'primary_unit': 'a/b/c', 'base_unit': 'a/b/c'}) self.assertDictEqual( unitconv.parse_unitname(''), {'multiplier': 1, 'unit_class': None, 'primary_unit': '', 'base_unit': ''})
def test_fractional(self): self.assertDictEqual( unitconv.parse_unitname('GB/h'), {'numer_multiplier': 1e9 * 8, 'denom_multiplier': 3600, 'multiplier': 1e9 * 8 / 3600, 'numer_unit_class': 'datasize', 'denom_unit_class': 'time', 'unit_class': 'datasize/time', 'numer_primary_unit': 'b', 'denom_primary_unit': 's', 'primary_unit': 'b/s', 'numer_base_unit': 'B', 'denom_base_unit': 'h', 'base_unit': 'B/h'}) self.assertDictEqual( unitconv.parse_unitname('kb/k', fold_scale_prefix=False), {'numer_multiplier': 1, 'denom_multiplier': 1, 'multiplier': 1, 'numer_scale_multiplier': 1000, 'denom_scale_multiplier': 1, 'scale_multiplier': 1000, 'numer_unit_class': 'datasize', 'denom_unit_class': None, 'unit_class': None, 'numer_primary_unit': 'b', 'denom_primary_unit': 'k', 'primary_unit': 'b/k', 'numer_base_unit': 'b', 'denom_base_unit': 'k', 'base_unit': 'b/k'}) self.assertDictEqual( unitconv.parse_unitname('Foobity/w', fold_scale_prefix=False), {'numer_multiplier': 1, 'denom_multiplier': 86400 * 7, 'multiplier': 1 / (86400 * 7), 'numer_scale_multiplier': 1, 'denom_scale_multiplier': 1, 'scale_multiplier': 1, 'numer_unit_class': None, 'denom_unit_class': 'time', 'unit_class': None, 'numer_primary_unit': 'Foobity', 'denom_primary_unit': 's', 'primary_unit': 'Foobity/s', 'numer_base_unit': 'Foobity', 'denom_base_unit': 'w', 'base_unit': 'Foobity/w'})
def run_scenario(user_asked_for, data_exists_as, allow_derivation=True, allow_integration=False, allow_prefixes_in_denominator=False, round_result=6): userunit = unitconv.parse_unitname(user_asked_for) compatibles = unitconv.determine_compatible_units( allow_derivation=allow_derivation, allow_integration=allow_integration, allow_prefixes_in_denominator=allow_prefixes_in_denominator, **userunit) try: scale, extra_op = compatibles[data_exists_as] except KeyError: return if round_result is not None: scale = round(scale, round_result) return (data_exists_as, scale, extra_op)
def run_scenario(user_asked_for, data_exists_as, allow_derivation=True, allow_integration=False, allow_prefixes_in_denominator=False, round_result=6): userunit = unitconv.parse_unitname(user_asked_for, fold_scale_prefix=False) prefixclass = unitconv.prefix_class_for(userunit['scale_multiplier']) use_unit = userunit['base_unit'] compatibles = unitconv.determine_compatible_units( allow_derivation=allow_derivation, allow_integration=allow_integration, allow_prefixes_in_denominator=allow_prefixes_in_denominator, **userunit) try: scale, extra_op = compatibles[data_exists_as] except KeyError: return if round_result is not None: scale = round(scale, round_result) return (data_exists_as, use_unit, scale, extra_op, prefixclass)
def transform_ast_for_compatible_units(cls, ast): if ast[0] == 'match_tag_equality' and ast[1] == 'unit': requested_unit = ast[2] unitinfo = unitconv.parse_unitname(requested_unit, fold_scale_prefix=False) prefixclass = unitconv.prefix_class_for( unitinfo['scale_multiplier']) use_unit = unitinfo['base_unit'] compatibles = unitconv.determine_compatible_units(**unitinfo) # rewrite the search term to include all the alternates ast = ('match_or', ) + tuple([('match_tag_equality', 'unit', u) for u in compatibles.keys()]) modifiers = [ cls.convert_to_requested_unit_applier(compatibles), cls.variable_applier(unit=use_unit) ] if prefixclass == 'binary': modifiers.append( cls.graph_config_applier(suffixes=prefixclass)) return ast, modifiers elif ast[0] in ('match_and', 'match_or'): # recurse into subexpressions, in case they have unit=* terms # underneath. this won't be totally correct in case there's a way # to have multiple "unit=*" terms inside varying structures of # 'and' and 'or', but that's not exposed to the user yet anyway, # and auto-unit-conversion in that case probably isn't worth # supporting. new_target_modifiers = [] newargs = [] for sub_ast in ast[1:]: if isinstance(sub_ast, tuple): sub_ast, mods = cls.transform_ast_for_compatible_units( sub_ast) new_target_modifiers.extend(mods) newargs.append(sub_ast) ast = (ast[0], ) + tuple(newargs) return ast, new_target_modifiers return ast, []
def transform_ast_for_compatible_units(cls, ast): if ast[0] == 'match_tag_equality' and ast[1] == 'unit': requested_unit = ast[2] unitinfo = unitconv.parse_unitname(requested_unit, fold_scale_prefix=False) prefixclass = unitconv.prefix_class_for(unitinfo['scale_multiplier']) use_unit = unitinfo['base_unit'] compatibles = unitconv.determine_compatible_units(**unitinfo) # rewrite the search term to include all the alternates ast = ('match_or',) + tuple( [('match_tag_equality', 'unit', u) for u in compatibles.keys()]) modifiers = [ cls.convert_to_requested_unit_applier(compatibles), cls.variable_applier(unit=use_unit) ] if prefixclass == 'binary': modifiers.append(cls.graph_config_applier(suffixes=prefixclass)) return ast, modifiers elif ast[0] in ('match_and', 'match_or'): # recurse into subexpressions, in case they have unit=* terms # underneath. this won't be totally correct in case there's a way # to have multiple "unit=*" terms inside varying structures of # 'and' and 'or', but that's not exposed to the user yet anyway, # and auto-unit-conversion in that case probably isn't worth # supporting. new_target_modifiers = [] newargs = [] for sub_ast in ast[1:]: if isinstance(sub_ast, tuple): sub_ast, mods = cls.transform_ast_for_compatible_units(sub_ast) new_target_modifiers.extend(mods) newargs.append(sub_ast) ast = (ast[0],) + tuple(newargs) return ast, new_target_modifiers return ast, []