def format_units(self, value, unit="<STR_LIT:B>", optimal=<NUM_LIT:5>, auto=True, si=False):
UNITS = "<STR_LIT>"<EOL>DECIMAL_SIZE = <NUM_LIT:1000><EOL>BINARY_SIZE = <NUM_LIT><EOL>CUTOFF = <NUM_LIT:1000><EOL>can_round = False<EOL>if unit:<EOL><INDENT>if unit[<NUM_LIT:0>].upper() in UNITS:<EOL><INDENT>index = UNITS.index(unit[<NUM_LIT:0>].upper()) + <NUM_LIT:1><EOL>post = unit[<NUM_LIT:1>:]<EOL>si = len(unit) > <NUM_LIT:1> and unit[<NUM_LIT:1>] != "<STR_LIT:i>"<EOL>if si:<EOL><INDENT>post = post[<NUM_LIT:1>:]<EOL>if unit[<NUM_LIT:1>] == "<STR_LIT:b>":<EOL><INDENT>value *= <NUM_LIT:8><EOL><DEDENT><DEDENT>auto = False<EOL><DEDENT>else:<EOL><INDENT>index = <NUM_LIT:0><EOL>post = unit<EOL><DEDENT><DEDENT>if si:<EOL><INDENT>size = DECIMAL_SIZE<EOL><DEDENT>else:<EOL><INDENT>size = BINARY_SIZE<EOL><DEDENT>if auto:<EOL><INDENT>if value < CUTOFF:<EOL><INDENT>unit_out = post<EOL><DEDENT>else:<EOL><INDENT>value /= size<EOL>for prefix in UNITS:<EOL><INDENT>if abs(value) < CUTOFF:<EOL><INDENT>break<EOL><DEDENT>value /= size<EOL><DEDENT>if si:<EOL><INDENT>if prefix == "<STR_LIT>":<EOL><INDENT>prefix = "<STR_LIT:k>"<EOL><DEDENT><DEDENT>else:<EOL><INDENT>post = "<STR_LIT:i>" + post<EOL><DEDENT>unit_out = prefix + post<EOL>can_round = True<EOL><DEDENT><DEDENT>else:<EOL><INDENT>unit_out = unit<EOL>size = pow(size, index)<EOL>if size:<EOL><INDENT>value /= size<EOL>can_round = True<EOL><DEDENT><DEDENT>if can_round and optimal and value:<EOL><INDENT>places = int(log10(abs(value)))<EOL>if places >= optimal - <NUM_LIT:2>:<EOL><INDENT>value = int(value)<EOL><DEDENT>else:<EOL><INDENT>value = round(value, max(optimal - places - <NUM_LIT:2>, <NUM_LIT:0>))<EOL><DEDENT><DEDENT>return value, unit_out<EOL>
Takes a value and formats it for user output, we can choose the unit to
use eg B, MiB, kbits/second.  This is mainly for use with bytes/bits it
converts the value into a human readable form.  It has various
additional options but they are really only for special cases.

The function returns a tuple containing the new value (this is a number
so that the user can still format it if required) and a unit that is
the units that we have been converted to.

By supplying unit to the function we can force those units to be used
eg ``unit=KiB`` would force the output to be in Kibibytes.  By default we
use non-si units but if the unit is si eg kB then we will switch to si
units.  Units can also be things like ``Mbit/sec``.

If the auto parameter is False then we use the unit provided.  This
only makes sense when the unit is singular eg 'Bytes' and we want the
result in bytes and not say converted to MBytes.

optimal is used to control the size of the output value.  We try to
provide an output value of that number of characters (including decimal
point), it may also be less due to rounding.  If a fixed unit is used
the output may be more than this number of characters.