Pretty print with unit and physical suffix II Follow up of Pretty print with unit and physical suffix

My first code didn't process negative numbers correctly. Additionally I tried to use all of the helpful input to come up with this solution.

I considered:


precision
testing
spacing tips


P.S.: I use the 'u' instead of U+03BC because I had some difficulties displaying it on my Windows console.

# -*- coding: utf-8 -*-

import math

def eng_format(x, unit='', precision=3):
    UNITS = [' ', ' k', ' M', ' G'] + \
            ([None] * 10) + \
            [' f', ' p', ' n', ' u', ' m']

    power_of_1000 = int(math.floor(math.log10(abs(x)) // 3))
    exponent = 3 * power_of_1000
    prefix = UNITS[power_of_1000]
    if prefix is None:
        prefix = '*10^%d ' % exponent

    predecimal = 1+int(math.floor(math.log10(abs(x)) % 3))
    significand = x * 10**(-exponent + precision - predecimal)
    significand = round(significand) / 10**(precision - predecimal)

    postdecimal = precision - predecimal
    if(postdecimal &lt; 0):
        postdecimal = 0
    FormatStr = '{:.%df}{:s}{:s}'%(postdecimal)
    return FormatStr.format(significand, prefix, unit)

if __name__ == '__main__':
    import unittest

    class TestPrettyPrinting(unittest.TestCase):
        def setUp(self):
            self.seq = list()
            self.seq.append( (0.002777, 'V', 3, '2.78 mV') )
            self.seq.append( (0.02777, 'V', 3, '27.8 mV') )
            self.seq.append( (0.2777, 'V', 3, '278 mV') )
            self.seq.append( (2.777, 'V', 3, '2.78 V') )
            self.seq.append( (27.77, 'V', 3, '27.8 V') )
            self.seq.append( (2./3, 'V', 6, '666.667 mV') )
            self.seq.append( (0.000003221, 'A', 3, '3.22 uA') )
            self.seq.append( (30589, 'A', 4, '30.59 kA') )
            self.seq.append( (60000000, 'W', 6, '60.0000 MW') )
            self.seq.append( (6000000000000000, 'W', 1, '6*10^15 W') )
            self.seq.append( (.0000000000000006, 'W', 4, '600.0*10^-18 W') )

        def test_eng_format(self):
            for value, unit, precission, expected_result in self.seq:
                for si, s in enumerate(['', '-']):
                    new_expected_result = s + expected_result
                    result = eng_format(value * (-1)**si, unit, precission)
                    print "%20s %20s"%(result, new_expected_result)
                    self.assertEqual(result, new_expected_result)

    unittest.main()
The computation of postdecimal can be simplified to postdecimal = max(precision - predecimal, 0).

eng_format needs a docstring.

On self.seq:


It needs a meaningful name like examples.
It should be local to test_eng_format, since that's the only place it's used.
It can be built in one expression, without mutation:

examples = [(0.002777, 'V', 3, '2.78 mV'),
            (0.02777, 'V', 3, '27.8 mV'),
            ...]

However, looping over a list of test cases is less readable than a bunch of self.assertEqual(eng_format(-0.1, 'A', 6), '-100.000 mA') calls.


test_eng_format should not print all its test cases. Tests should be silent unless they fail.