manuel di lullo https github commanueldilullo description convert a number to use the correct si or binary unit prefix inspired by prefixconversion py file in this repository by lancepyles url https en wikipedia orgwikimetricprefixlistofsiprefixes url https en wikipedia orgwikibinaryprefix create a generic variable that can be enum or any subclass returns a dictionary with only the elements of this enum that has a positive value from itertools import islice positive siunit getpositive inc iterpositive items dictisliceinc lenpositive 2 yotta 24 zetta 21 exa 18 peta 15 tera 12 dictinc giga 9 mega 6 kilo 3 hecto 2 deca 1 returns a dictionary with only the elements of this enum that has a negative value example from itertools import islice negative siunit getnegative inc iternegative items dictisliceinc lennegative 2 deci 1 centi 2 milli 3 micro 6 nano 9 dictinc pico 12 femto 15 atto 18 zepto 21 yocto 24 function that converts a number to his version with si prefix input value an integer example addsiprefix10000 10 0 kilo function that converts a number to his version with binary prefix input value an integer example addbinaryprefix65536 64 0 kilo create a generic variable that can be enum or any subclass returns a dictionary with only the elements of this enum that has a positive value from itertools import islice positive siunit get_positive inc iter positive items dict islice inc len positive 2 yotta 24 zetta 21 exa 18 peta 15 tera 12 dict inc giga 9 mega 6 kilo 3 hecto 2 deca 1 returns a dictionary with only the elements of this enum that has a negative value example from itertools import islice negative siunit get_negative inc iter negative items dict islice inc len negative 2 deci 1 centi 2 milli 3 micro 6 nano 9 dict inc pico 12 femto 15 atto 18 zepto 21 yocto 24 function that converts a number to his version with si prefix input value an integer example add_si_prefix 10000 10 0 kilo function that converts a number to his version with binary prefix input value an integer example add_binary_prefix 65536 64 0 kilo
from __future__ import annotations

from enum import Enum, unique
from typing import TypeVar


T = TypeVar("T", bound="Enum")


@unique
class BinaryUnit(Enum):
    yotta = 80
    zetta = 70
    exa = 60
    peta = 50
    tera = 40
    giga = 30
    mega = 20
    kilo = 10


@unique
class SIUnit(Enum):
    yotta = 24
    zetta = 21
    exa = 18
    peta = 15
    tera = 12
    giga = 9
    mega = 6
    kilo = 3
    hecto = 2
    deca = 1
    deci = -1
    centi = -2
    milli = -3
    micro = -6
    nano = -9
    pico = -12
    femto = -15
    atto = -18
    zepto = -21
    yocto = -24

    @classmethod
    def get_positive(cls: type[T]) -> dict:
        
        return {unit.name: unit.value for unit in cls if unit.value > 0}

    @classmethod
    def get_negative(cls: type[T]) -> dict:
        
        return {unit.name: unit.value for unit in cls if unit.value < 0}


def add_si_prefix(value: float) -> str:
    
    prefixes = SIUnit.get_positive() if value > 0 else SIUnit.get_negative()
    for name_prefix, value_prefix in prefixes.items():
        numerical_part = value / (10**value_prefix)
        if numerical_part > 1:
            return f"{numerical_part!s} {name_prefix}"
    return str(value)


def add_binary_prefix(value: float) -> str:
    
    for prefix in BinaryUnit:
        numerical_part = value / (2**prefix.value)
        if numerical_part > 1:
            return f"{numerical_part!s} {prefix.name}"
    return str(value)


if __name__ == "__main__":
    import doctest

    doctest.testmod()