def _currencyfmt(self, value):
        if not self.currency_enabled:
            return ()
        if not isinstance(value, (float, decimal.Decimal)):
            if self.currency_float_only:
                return ()

        value = decimal.Decimal(value)

        if self.currency_from_system:
            value_to_api = str(float(value))
            try:
                # use the GetCurrencyFormatEx windows api to format the value
                GetCurrencyFormatEx = kpwt.declare_func(
                    kpwt.kernel32, "GetCurrencyFormatEx", ret=kpwt.ct.c_int,
                    arg=[kpwt.LPCWSTR, kpwt.DWORD, kpwt.LPCWSTR, kpwt.LPVOID, kpwt.PWSTR, kpwt.ct.c_int])
                buf = kpwt.ct.create_unicode_buffer(128)
                res = GetCurrencyFormatEx(
                    None, 0, value_to_api, None, buf, len(buf))
                if res > 0 and len(buf.value) > 0:
                    return (buf.value,)
            except:
                traceback.print_exc()
            self.info(
                "Failed to ask system to currency format value \"{}\". " +
                "Falling back to manual method.".format(value_to_api))

        # manual mode
        # note that this code block may be used as a fallback method in case the
        # above code failed to ask windows api to format the value
        formatted_value = self._currencyfmt_impl(
            value, places=self.currency_places,
            sep=self.currency_thousandsep, dp=self.currency_decsep)
        return (formatted_value,)
Example #2
0
    def get_separators(self):
        # [main] decimal_separator
        decimal_separator = "."
        thousand_separator = ""
        transmap_output = str.maketrans("", "", ",")
        config_decsep = self.settings.get_enum("decimal_separator",
                                               "main",
                                               fallback="dot",
                                               enum=["dot", "comma", "auto"])
        if config_decsep == "auto":
            thousand_separator = " "
            try:
                # use the GetLocaleInfoEx windows api to get the decimal and
                # thousand separators configured by system's user
                GetLocaleInfoEx = kpwt.declare_func(
                    kpwt.kernel32,
                    "GetLocaleInfoEx",
                    ret=kpwt.ct.c_int,
                    args=[kpwt.LPCWSTR, kpwt.DWORD, kpwt.PWSTR, kpwt.ct.c_int])
                LOCALE_SDECIMAL = 0x0000000E
                LOCALE_STHOUSAND = 0x0000000F

                # decimal separator
                buf = kpwt.ct.create_unicode_buffer(10)
                res = GetLocaleInfoEx(None, LOCALE_SDECIMAL, buf, len(buf))
                if res == 2 and len(buf.value) == res - 1 and buf.value == ",":
                    decimal_separator = ","
                # thousand separator
                # quite awful to have a try block here but we take advantage of
                # having GetLocaleInfoEx already defined
                try:
                    buf = kpwt.ct.create_unicode_buffer(10)
                    res = GetLocaleInfoEx(None, LOCALE_STHOUSAND, buf,
                                          len(buf))
                    if res == 2 and len(buf.value) == res - 1:
                        thousand_separator = buf.value
                except Exception:
                    traceback.print_exc()

                transmap_output = str.maketrans(
                    ".,", f"{decimal_separator}{thousand_separator}")
            except Exception:
                self.warn(
                    "Failed to get system user decimal and thousand separators. "
                    +  # noqa
                    "Falling back to default (" + config_decsep + ")...")
                traceback.print_exc()
            self.info(f'Using "{decimal_separator}" as a decimal separator')
        if config_decsep == "comma":
            decimal_separator = ","
            thousand_separator = " "
            transmap_output = str.maketrans(
                ".,", f"{decimal_separator}{thousand_separator}")

        return (decimal_separator, thousand_separator, transmap_output)
Example #3
0
    def _currencyfmt(self, value):
        if not self.currency_enabled:
            return ()
        if not isinstance(value, (float, Number)):
            if self.currency_float_only:
                return ()

        value = Number(value)

        if self.currency_from_system:
            value_to_api = str(float(value))
            try:
                # use the GetCurrencyFormatEx windows api to format the value
                GetCurrencyFormatEx = kpwt.declare_func(
                    kpwt.kernel32,
                    "GetCurrencyFormatEx",
                    ret=kpwt.ct.c_int,
                    args=[
                        kpwt.LPCWSTR, kpwt.DWORD, kpwt.LPCWSTR, kpwt.LPVOID,
                        kpwt.PWSTR, kpwt.ct.c_int
                    ])
                buf = kpwt.ct.create_unicode_buffer(128)
                res = GetCurrencyFormatEx(None, 0, value_to_api, None, buf,
                                          len(buf))
                if res > 0 and len(buf.value) > 0:
                    return (buf.value, )
            except:
                traceback.print_exc()
                self.info('Failed to ask system to currency format value "' +
                          str(value_to_api) + '". ' +
                          'Falling back to manual method.')

        # manual mode
        # note that this code block may be used as a fallback method in case the
        # above code failed to ask windows api to format the value
        formatted_value = self._currencyfmt_impl(value,
                                                 places=self.currency_places,
                                                 sep=self.currency_thousandsep,
                                                 dp=self.currency_decsep)
        if self.currency_decsep in formatted_value:
            formatted_value = formatted_value.rstrip("0").rstrip(
                self.currency_decsep)
            if not len(formatted_value):
                formatted_value = "0"
        return (formatted_value, )
Example #4
0
    def _read_config(self):
        settings = self.load_settings()

        # [main] always_evaluate
        self.always_evaluate = settings.get_bool("always_evaluate", "main",
                                                 self.DEFAULT_ALWAYS_EVALUATE)

        # [main] decimal_separator
        DEFAULT_DECIMAL_SEPARATOR = "dot"
        self.decimal_separator = "."
        self.thousand_separator = ","
        config_decsep = settings.get_enum("decimal_separator",
                                          "main",
                                          fallback=DEFAULT_DECIMAL_SEPARATOR,
                                          enum=["dot", "comma", "auto"])
        if config_decsep == "auto":
            config_decsep = DEFAULT_DECIMAL_SEPARATOR
            try:
                # use the GetLocaleInfoEx windows api to get the decimal and
                # thousand separators configured by system's user
                GetLocaleInfoEx = kpwt.declare_func(
                    kpwt.kernel32,
                    "GetLocaleInfoEx",
                    ret=kpwt.ct.c_int,
                    args=[kpwt.LPCWSTR, kpwt.DWORD, kpwt.PWSTR, kpwt.ct.c_int])
                LOCALE_SDECIMAL = 0x0000000E
                LOCALE_STHOUSAND = 0x0000000F

                # decimal separator
                buf = kpwt.ct.create_unicode_buffer(10)
                res = GetLocaleInfoEx(None, LOCALE_SDECIMAL, buf, len(buf))
                if res == 2 and len(buf.value) == res - 1 and buf.value == ",":
                    config_decsep = "comma"

                # thousand separator
                # quite awful to have a try block here but we take advantage of
                # having GetLocaleInfoEx already defined
                try:
                    buf = kpwt.ct.create_unicode_buffer(10)
                    res = GetLocaleInfoEx(None, LOCALE_STHOUSAND, buf,
                                          len(buf))
                    if res > 0:
                        self.thousand_separator = buf
                except:
                    traceback.print_exc()
            except:
                self.warn(
                    "Failed to get system user decimal and thousand separators. "
                    + "Falling back to default (" + config_decsep + ")...")
                traceback.print_exc()
            self.info(
                "Using \"{}\" as a decimal separator".format(config_decsep))
        if config_decsep == "comma":
            self.decimal_separator = ","
            self.thousand_separator = " "
            self.transmap_input = str.maketrans(",;", ".,")
            self.transmap_output = str.maketrans(".", ",")
        else:
            self.decimal_separator = "."
            self.thousand_separator = ","
            self.transmap_input = ""
            self.transmap_output = ""

        # [main] base conversion
        self.base_conversion = settings.get_bool("base_conversion", "main",
                                                 self.DEFAULT_BASE_CONVERSION)

        # [main] rounding_precision
        if not settings.has("rounding_precision", "main"):
            self.rounding_precision = self.DEFAULT_ROUNDING_PRECISION
        elif None == settings.get_stripped("rounding_precision",
                                           "main",
                                           fallback=None):
            self.rounding_precision = None  # None means "feature disabled"
        else:
            self.rounding_precision = settings.get_int(
                "rounding_precision",
                "main",
                fallback=self.DEFAULT_ROUNDING_PRECISION,
                min=0,
                max=16)
            self.rounding_precision += 1

        # [currency] mode
        cfgval = settings.get_enum("mode",
                                   "currency",
                                   fallback=self.DEFAULT_CURRENCY_MODE,
                                   enum=["on", "float", "off"])
        if cfgval == "off":
            self.currency_enabled = False
            self.currency_float_only = True
        else:
            self.currency_enabled = True
            self.currency_float_only = True if cfgval == "float" else False

        # [currency] format
        cfgval = settings.get_enum("format",
                                   "currency",
                                   fallback=self.DEFAULT_CURRENCY_FORMAT,
                                   enum=["system", "manual"])
        self.currency_from_system = False if cfgval == "manual" else True

        # [currency] decimal_separator
        self.currency_decsep = settings.get_stripped(
            "decimal_separator",
            "currency",
            fallback=self.DEFAULT_CURRENCY_DECIMALSEP)
        if len(self.currency_decsep) == 0 or len(self.currency_decsep) > 4:
            self.currency_decsep = self.DEFAULT_CURRENCY_DECIMALSEP

        # [currency] thousand_separator
        self.currency_thousandsep = settings.get(
            "thousand_separator",
            "currency",
            fallback=self.DEFAULT_CURRENCY_THOUSANDSEP,
            unquote=True)
        if len(self.currency_thousandsep) > 4:
            self.currency_thousandsep = self.DEFAULT_CURRENCY_THOUSANDSEP

        # [currency] places
        self.currency_places = settings.get_int(
            "places",
            "currency",
            fallback=self.DEFAULT_CURRENCY_PLACES,
            min=0,
            max=5)
    def _read_config(self):
        settings = self.load_settings()

        # [main] always_evaluate
        self.always_evaluate = settings.get_bool("always_evaluate", "main",
                                                 self.DEFAULT_ALWAYS_EVALUATE)

        # [main] decimal_separator
        DEFAULT_DECIMAL_SEPARATOR = "dot"
        decimal_separator = settings.get_enum(
            "decimal_separator",
            "main",
            fallback=DEFAULT_DECIMAL_SEPARATOR,
            enum=["dot", "comma", "auto"])
        if decimal_separator == "auto":
            decimal_separator = DEFAULT_DECIMAL_SEPARATOR
            try:
                # use the GetLocaleInfoEx windows api to get the decimal
                # separator configured by system's user
                GetLocaleInfoEx = kpwt.declare_func(
                    kpwt.kernel32,
                    "GetLocaleInfoEx",
                    ret=kpwt.ct.c_int,
                    arg=[kpwt.LPCWSTR, kpwt.DWORD, kpwt.PWSTR, kpwt.ct.c_int])
                LOCALE_SDECIMAL = 0x0000000E
                buf = kpwt.ct.create_unicode_buffer(10)
                res = GetLocaleInfoEx(None, LOCALE_SDECIMAL, buf, len(buf))
                if res == 2 and len(buf.value) == res - 1 and buf.value == ",":
                    decimal_separator = "comma"
            except:
                self.warn(
                    "Failed to get system user decimal separator value. " +
                    "Falling back to default (" + decimal_separator + ")...")
                traceback.print_exc()
            self.info("Using \"{}\" as a decimal separator".format(
                decimal_separator))
        if decimal_separator == "comma":
            self.transmap_input = str.maketrans(",;", ".,")
            self.transmap_output = str.maketrans(".", ",")
        else:
            self.transmap_input = ""
            self.transmap_output = ""

        # [currency] mode
        cfgval = settings.get_enum("mode",
                                   "currency",
                                   fallback=self.DEFAULT_CURRENCY_MODE,
                                   enum=["on", "float", "off"])
        if cfgval == "off":
            self.currency_enabled = False
            self.currency_float_only = True
        else:
            self.currency_enabled = True
            self.currency_float_only = True if cfgval == "float" else False

        # [currency] format
        cfgval = settings.get_enum("format",
                                   "currency",
                                   fallback=self.DEFAULT_CURRENCY_FORMAT,
                                   enum=["system", "manual"])
        self.currency_from_system = False if cfgval == "manual" else True

        # [currency] decimal_separator
        self.currency_decsep = settings.get_stripped(
            "decimal_separator",
            "currency",
            fallback=self.DEFAULT_CURRENCY_DECIMALSEP)
        if len(self.currency_decsep) == 0 or len(self.currency_decsep) > 4:
            self.currency_decsep = self.DEFAULT_CURRENCY_DECIMALSEP

        # [currency] thousand_separator
        self.currency_thousandsep = settings.get(
            "thousand_separator",
            "currency",
            fallback=self.DEFAULT_CURRENCY_THOUSANDSEP,
            unquote=True)
        if len(self.currency_thousandsep) > 4:
            self.currency_thousandsep = self.DEFAULT_CURRENCY_THOUSANDSEP

        # [currency] places
        self.currency_places = settings.get_int(
            "places",
            "currency",
            fallback=self.DEFAULT_CURRENCY_PLACES,
            min=0,
            max=5)
    def _read_config(self):
        settings = self.load_settings()

        # [main] always_evaluate
        self.always_evaluate = settings.get_bool(
            "always_evaluate", "main", self.DEFAULT_ALWAYS_EVALUATE)

        # [main] decimal_separator
        DEFAULT_DECIMAL_SEPARATOR = "dot"
        decimal_separator = settings.get_enum(
            "decimal_separator", "main",
            fallback=DEFAULT_DECIMAL_SEPARATOR,
            enum=["dot", "comma", "auto"])
        if decimal_separator == "auto":
            decimal_separator = DEFAULT_DECIMAL_SEPARATOR
            try:
                # use the GetLocaleInfoEx windows api to get the decimal
                # separator configured by system's user
                GetLocaleInfoEx = kpwt.declare_func(
                    kpwt.kernel32, "GetLocaleInfoEx", ret=kpwt.ct.c_int,
                    arg=[kpwt.LPCWSTR, kpwt.DWORD, kpwt.PWSTR, kpwt.ct.c_int])
                LOCALE_SDECIMAL = 0x0000000E
                buf = kpwt.ct.create_unicode_buffer(10)
                res = GetLocaleInfoEx(None, LOCALE_SDECIMAL, buf, len(buf))
                if res == 2 and len(buf.value) == res - 1 and buf.value == ",":
                    decimal_separator = "comma"
            except:
                self.warn(
                    "Failed to get system user decimal separator value. " +
                    "Falling back to default (" + decimal_separator + ")...")
                traceback.print_exc()
            self.info("Using \"{}\" as a decimal separator".format(decimal_separator))
        if decimal_separator == "comma":
            self.transmap_input = str.maketrans(",;", ".,")
            self.transmap_output = str.maketrans(".", ",")
        else:
            self.transmap_input = ""
            self.transmap_output = ""

        # [currency] mode
        cfgval = settings.get_enum(
            "mode", "currency",
            fallback=self.DEFAULT_CURRENCY_MODE,
            enum=["on", "float", "off"])
        if cfgval == "off":
            self.currency_enabled = False
            self.currency_float_only = True
        else:
            self.currency_enabled = True
            self.currency_float_only = True if cfgval == "float" else False

        # [currency] format
        cfgval = settings.get_enum(
            "format", "currency",
            fallback=self.DEFAULT_CURRENCY_FORMAT,
            enum=["system", "manual"])
        self.currency_from_system = False if cfgval == "manual" else True

        # [currency] decimal_separator
        self.currency_decsep = settings.get_stripped(
            "decimal_separator", "currency",
            fallback=self.DEFAULT_CURRENCY_DECIMALSEP)
        if len(self.currency_decsep) == 0 or len(self.currency_decsep) > 4:
            self.currency_decsep = self.DEFAULT_CURRENCY_DECIMALSEP

        # [currency] thousand_separator
        self.currency_thousandsep = settings.get(
            "thousand_separator", "currency",
            fallback=self.DEFAULT_CURRENCY_THOUSANDSEP,
            unquote=True)
        if len(self.currency_thousandsep) > 4:
            self.currency_thousandsep = self.DEFAULT_CURRENCY_THOUSANDSEP

        # [currency] places
        self.currency_places = settings.get_int(
            "places", "currency",
            fallback=self.DEFAULT_CURRENCY_PLACES,
            min=0, max=5)