modm-io / lbuild

lbuild: a generic, modular code generator in Python 3
https://pypi.org/project/lbuild
BSD 2-Clause "Simplified" License
37 stars 12 forks source link

Add support for value multipliers (and maybe units)? #77

Closed cocasema closed 2 years ago

cocasema commented 2 years ago

(This comes from the usage in modm)

I think it might be a bit more user friendly to allow users specifying units in some lbuild options. An example could be

    <option name="modm:platform:core:boot2_size">8MiB</option>

now it's

    <option name="modm:platform:core:boot2_size">8*1024*1024</option>

which is already way better than what I originally had (failed to RTFM and find out the NumericOption can do basic math)

    <option name="modm:platform:core:boot2_size">8388608/option>

Even if the existing NumericOption.as_numeric_value modified a bit, it can be used to allow M/Mi multipliers (although w/o units):

    def as_numeric_value(self, value):
        if value is None:
            return value
        if isinstance(value, (int, float)):
            return value
        if isinstance(value, str):
            try:
### new code
                suffix = ""
                for idx in [1, 2]:
                    if 1 < len(value) and value[-1].isalpha():
                        suffix = value[-1] + suffix
                        value = value[:-1]

                if suffix:
                    multiplier = {
                        "K": " * 1000",
                        "M": " * 1000 * 1000",
                        "G": " * 1000 * 1000 * 1000",
                        "T": " * 1000 * 1000 * 1000 * 1000",
                        "Ki": " * 1024",
                        "Mi": " * 1024 * 1024",
                        "Gi": " * 1024 * 1024 * 1024",
                        "Ti": " * 1024 * 1024 * 1024 * 1024",
                    }.get(suffix)
                    if not multiplier:
                        raise TypeError("Unknown numeric multiplier '{}'! Supported are: {}".format(suffix), ", ".join(multiplier.keys()))
                    value += multiplier
### end
                value = eval(value)
                if isinstance(value, (int, float)):
                    return value
            except Exception as error:
                raise TypeError("Input must be numeric! {}".format(error))

        raise TypeError("Input must be numeric!")

This will parse

    <option name="modm:platform:core:boot2_size">8M</option>

or

    <option name="modm:platform:core:boot2_size">8Mi</option>

Would you find this addition useful ?

salkinium commented 2 years ago

Yes! Very good idea! The implementation is elegant too!

salkinium commented 2 years ago

Also, you could not have know that NumericOption does eval on the input, cos I forgot to update the docs. Ironically, inputs like "1/3" will now yield exact float values 🤦‍♂️