# 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 < 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.