@@ -1795,11 +1795,12 @@ def scale(self, scale, cls=None):
17951795 are taken to the be desired units and the behavior is the same as
17961796 if a string were given, except that *cls* defaults to the given
17971797 subclass.
1798+ :type scale: real, pair, function, string, or quantity
1799+
17981800 :arg class cls:
17991801 Class to use for return value. If not given, the class of self is
18001802 used it the units do not change, in which case :class:`Quantity` is
18011803 used.
1802- :type scale: real, pair, function, string, or quantity
18031804
18041805 :raises UnknownConversion(QuantiPhyError, KeyError):
18051806 A unit conversion was requested and there is no corresponding unit
@@ -3145,9 +3146,6 @@ def all_from_si_fmt(cls, text, **kwargs):
31453146# Unit Conversions {{{1
31463147# UnitConversion class {{{2
31473148class UnitConversion (object ):
3148- _unit_conversions = {}
3149- _known_units = set ()
3150-
31513149 # description {{{3
31523150 """
31533151 Creates a unit converter.
@@ -3286,6 +3284,11 @@ class UnitConversion(object):
32863284
32873285 """
32883286
3287+ _unit_conversions = {}
3288+ _known_units = set ()
3289+ _support_si_sf_scaling = True
3290+ _support_bin_sf_scaling = True
3291+
32893292 # constructor {{{3
32903293 def __init__ (self , to_units , from_units , slope = 1 , intercept = 0 ):
32913294 self .slope = slope
@@ -3465,6 +3468,26 @@ def clear_all(cls):
34653468 cls ._unit_conversions = {}
34663469 cls ._known_units = set ()
34673470
3471+ @classmethod
3472+ def enable_scaling (cls , si_scaling = None , bin_scaling = None ):
3473+ """By default the given or desired units in a unit conversion or scaling
3474+ may include scale factors. This is true for both SI and binary scale
3475+ factors. The scale factor is provided as a prefix on the units. In
3476+ rare cases the acceptance of scale factors may create problems. You can
3477+ use this method to disable support for interpreting scale factors in
3478+ unit conversions.
3479+
3480+ si_scaling (bool):
3481+ Enables or disables support for SI scale factor scaling.
3482+
3483+ bin_scaling (bool):
3484+ Enables or disables support for binary scale factor scaling.
3485+ """
3486+ if si_scaling is not None :
3487+ cls ._support_si_sf_scaling = si_scaling
3488+ if bin_scaling is not None :
3489+ cls ._support_bin_sf_scaling = bin_scaling
3490+
34683491 # fixture() {{{3
34693492 @staticmethod
34703493 def fixture (converter_func ):
@@ -3569,6 +3592,8 @@ def _convert_units(cls, to_units, from_units, value):
35693592 # If you want this functionality, simply use:
35703593 # Quantity(value, from_units).scale(to_units)
35713594
3595+ orig_to_units , orig_from_units = to_units , from_units
3596+
35723597 def get_converter (to_units , from_units ):
35733598 # handle unity scale factor conversions
35743599 if (
@@ -3586,45 +3611,43 @@ def get_converter(to_units, from_units):
35863611 # b. there is no scale factor on the from_units
35873612 # c. there are scale factors on both the to_ and from_units
35883613
3614+ # separate scale factor from units
3615+ def extract_sf (units ):
3616+ # check for binary scale factor, all of which are two characters
3617+ if cls ._support_bin_sf_scaling :
3618+ sf , unit = units [:2 ], units [2 :]
3619+ if sf in BINARY_MAPPINGS :
3620+ return sf , unit , BINARY_MAPPINGS [sf ]
3621+
3622+ # check for SI scale factor, all of which are 1 character
3623+ if cls ._support_si_sf_scaling :
3624+ sf , unit = units [:1 ], units [1 :]
3625+ if sf in MAPPINGS :
3626+ return sf , unit , float ('1' + MAPPINGS [sf ])
3627+
3628+ return None , units , 1
3629+
3630+ # separate scale factor from units
35893631 # handle known-unit cases for to_units
3590- to_sf = None
3591- to_resolved = to_units in cls ._known_units # case 1
3592- if not to_resolved :
3593- to_prefix , to_suffix = to_units [:1 ], to_units [1 :]
3594- to_resolved = to_prefix in ALL_SF and to_suffix in cls ._known_units
3595- if to_resolved :
3596- to_sf , to_units = to_prefix , to_suffix # case 2
3632+ if to_units in cls ._known_units : # case 1
3633+ to_sf , to_scale = None , 1
3634+ else : # case 2 or 3
3635+ to_sf , to_units , to_scale = extract_sf (to_units )
35973636
35983637 # handle known-unit cases for from_units
3599- from_sf = None
3600- from_resolved = from_units in cls ._known_units # case 1
3601- if not from_resolved :
3602- from_prefix , from_suffix = from_units [:1 ], from_units [1 :]
3603- from_resolved = (
3604- from_prefix in ALL_SF and from_suffix in cls ._known_units
3605- )
3606- if from_resolved :
3607- from_sf , from_units = from_prefix , from_suffix # case 2
3608-
3609- # handle same-unit cases
3610- if not to_resolved and not from_resolved : # case 3
3611- if to_units == from_suffix and from_prefix in ALL_SF : # case 3a
3612- from_sf , from_units = from_prefix , from_suffix
3613- elif from_units == to_suffix and to_prefix in ALL_SF : # case 3b
3614- to_sf , to_units = to_prefix , to_suffix
3615- elif from_prefix in ALL_SF and to_prefix in ALL_SF : # case 3c
3616- to_sf , to_units = to_prefix , to_suffix
3617- from_sf , from_units = from_prefix , from_suffix
3638+ if from_units in cls ._known_units : # case 1
3639+ from_sf , from_scale = None , 1
3640+ else : # case 2 or 3
3641+ from_sf , from_units , from_scale = extract_sf (from_units )
36183642
3619- def get_sf (sf ):
3620- if sf is None :
3621- return 1
3622- return float ('1' + MAPPINGS [sf ])
3643+ # handle unknown unit cases (to- and from- must have same units)
3644+ if to_units == from_units : # case 3
3645+ return to_units , from_units , to_scale , from_scale
36233646
3624- if to_sf or from_sf :
3625- return to_units , from_units , get_sf ( to_sf ), get_sf ( from_sf )
3647+ if to_units in cls . _known_units or from_units in cls . _known_units : # case 2
3648+ return to_units , from_units , to_scale , from_scale
36263649
3627- raise UnknownConversion (to_units = to_units , from_units = from_units )
3650+ raise UnknownConversion (to_units = orig_to_units , from_units = orig_from_units )
36283651
36293652 to_units , from_units , to_sf , from_sf = get_converter (to_units , from_units )
36303653
@@ -3633,7 +3656,10 @@ def get_sf(sf):
36333656 value = Quantity (value , from_units )
36343657 if to_units == from_units :
36353658 return from_sf * value / to_sf
3636- converter = cls ._unit_conversions [(to_units , from_units )]
3659+ try :
3660+ converter = cls ._unit_conversions [(to_units , from_units )]
3661+ except KeyError :
3662+ raise UnknownConversion (to_units = orig_to_units , from_units = orig_from_units )
36373663 return converter (value .scale (from_sf )) / to_sf
36383664
36393665
@@ -3664,7 +3690,7 @@ def __str__(self):
36643690UnitConversion ('K' , 'R °R' , 5 / 9 , 0 )
36653691
36663692# Length/Distance conversions {{{2
3667- UnitConversion ('m' , 'micron' , 1 / 1000000 )
3693+ UnitConversion ('m' , 'micron microns ' , 1 / 1000000 )
36683694UnitConversion ('m' , 'Å angstrom' , 1 / 10000000000 )
36693695UnitConversion ('m' , 'mi mile miles' , 1609.344 )
36703696UnitConversion ('m' , 'ft feet' , 0.3048 )
0 commit comments