diff --git a/CHANGELOG.md b/CHANGELOG.md index 52774ee..52a8733 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ Changelog ========= +### [3.5][v3.5] ### + +Released 2018-01-12 + +- Add `DYNAMIC_DECIMALS` setting to expand the number of decimal places until the displayed result is non-zero. + + ### [3.4][v3.4] ### Released 2017-12-27 @@ -160,4 +167,5 @@ Released 2014-08-09. [v3.3]: https://github.com/deanishe/alfred-convert/releases/tag/v3.3 [v3.3.1]: https://github.com/deanishe/alfred-convert/releases/tag/v3.3.1 [v3.4]: https://github.com/deanishe/alfred-convert/releases/tag/v3.4 +[v3.5]: https://github.com/deanishe/alfred-convert/releases/tag/v3.5 [openx]: https://openexchangerates.org/ \ No newline at end of file diff --git a/Convert-3.4.alfredworkflow b/Convert-3.5.alfredworkflow similarity index 85% rename from Convert-3.4.alfredworkflow rename to Convert-3.5.alfredworkflow index 59c9133..4c8c4e0 100644 Binary files a/Convert-3.4.alfredworkflow and b/Convert-3.5.alfredworkflow differ diff --git a/README.md b/README.md index 81e1f09..0edf820 100644 --- a/README.md +++ b/README.md @@ -90,14 +90,15 @@ The workflow is configured via the configuration sheet (`[𝒙]`) in Alfred Pref Basic configuration is performed in the configuration sheet: -| Option | Meaning | -|-----------------------|----------------------------------------------------------------------------------------------------------| -| `APP_KEY` | API key for [openexchangerates.org][openx]. | -| `COPY_UNIT` | Include unit when copying conversion result. Any value but `0` or empty turns this option on. | -| `DECIMAL_PLACES` | Number of decimal places to show in results. | -| `DECIMAL_SEPARATOR` | Character to separate whole numbers and decimal fractions. Used for parsing input and generating output. | -| `THOUSANDS_SEPARATOR` | Character to delimit thousands Used for parsing input and generating output. | -| `UPDATE_INTERVAL` | How often (in minutes) to update currency exchange rates. | +| Option | Meaning | +|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------| +| `APP_KEY` | API key for [openexchangerates.org][openx]. | +| `COPY_UNIT` | Include unit when copying conversion result. Any value but `0` or empty turns this option on. | +| `DECIMAL_PLACES` | Number of decimal places to show in results. | +| `DECIMAL_SEPARATOR` | Character to separate whole numbers and decimal fractions. Used for parsing input and generating output. | +| `DYNAMIC_DECIMALS` | Dynamically increase the number of decimal places (up to 10) so that the result is non-zero. Any value but `0` or empty turns this option on. | +| `THOUSANDS_SEPARATOR` | Character to delimit thousands Used for parsing input and generating output. | +| `UPDATE_INTERVAL` | How often (in minutes) to update currency exchange rates. | #### Active currencies #### @@ -155,6 +156,8 @@ See [CHANGELOG][changelog] for more information. | Release | Date | |-----------------|----------------| +| [3.5][v3.5] | 2018-01-12 | +| [3.4][v3.4] | 2017-12-26 | | [3.3.1][v3.3.1] | 2017-11-21 | | [3.3][v3.3] | 2017-11-20 | | [3.2.2][v3.2.2] | 2017-11-07 | @@ -214,6 +217,8 @@ All other code/media are released under the [MIT Licence][mit]. [v3.2.2]: https://github.com/deanishe/alfred-convert/releases/tag/v3.2.2 [v3.3]: https://github.com/deanishe/alfred-convert/releases/tag/v3.3 [v3.3.1]: https://github.com/deanishe/alfred-convert/releases/tag/v3.3.1 +[v3.4]: https://github.com/deanishe/alfred-convert/releases/tag/v3.4 +[v3.5]: https://github.com/deanishe/alfred-convert/releases/tag/v3.5 [cryptocompare]: https://www.cryptocompare.com/ [openx]: https://openexchangerates.org/ [openx-free]: https://openexchangerates.org/signup/free diff --git a/src/config.py b/src/config.py index 50772dc..b7d7949 100644 --- a/src/config.py +++ b/src/config.py @@ -26,8 +26,10 @@ DECIMAL_SEPARATOR = os.getenv('DECIMAL_SEPARATOR') or '.' THOUSANDS_SEPARATOR = os.getenv('THOUSANDS_SEPARATOR') or '' +DYNAMIC_DECIMALS = os.getenv('DYNAMIC_DECIMALS', '') not in ('', '0') COPY_UNIT = os.getenv('COPY_UNIT', '') not in ('', '0') + # ---------------------------------------------------------------------- # Currency settings # ---------------------------------------------------------------------- diff --git a/src/convert.py b/src/convert.py index c0c6580..47d6b2a 100755 --- a/src/convert.py +++ b/src/convert.py @@ -31,6 +31,7 @@ DECIMAL_PLACES, DECIMAL_SEPARATOR, DEFAULT_SETTINGS, + DYNAMIC_DECIMALS, HELP_URL, ICON_UPDATE, NOKEY_FILENAME, @@ -153,11 +154,55 @@ class Formatter(object): """ def __init__(self, decimal_places=2, decimal_separator='.', - thousands_separator=''): + thousands_separator='', dynamic_decimals=True): """Create a new `Formatter`.""" self.decimal_places = decimal_places self.decimal_separator = decimal_separator self.thousands_separator = thousands_separator + self.dynamic_decimals = dynamic_decimals + + def _decimal_places(self, n): + """Calculate the number of decimal places the result should have. + + If :attr:`dynamic_decimals` is `True`, increase the number of + decimal places until the result is non-zero. + + Args: + n (float): Number that will be formatted. + + Returns: + int: Number of decimal places for result. + """ + log.debug('DYNAMIC_DECIMALS are %s', + ('off', 'on')[self.dynamic_decimals]) + + if not self.dynamic_decimals: + return self.decimal_places + + m = max(self.decimal_places, 10) + 1 + p = self.decimal_places + while p < m: + e = 10 ** p + i = n * e + # log.debug('n=%f, e=%d, i=%f, p=%d', n, e, i, p) + if n * e >= 10: + break + + p += 1 + + # Remove trailing zeroes + s = str(i) + if '.' not in s: # not a fraction + return p + + s = s.split('.')[-1] + # log.debug('s=%s, p=%d', s, p) + while s.endswith('0'): + s = s[:-1] + p -= 1 + # log.debug('s=%s, p=%d', s, p) + + return p def formatted(self, n, unit=None): """Format number with thousands and decimal separators.""" @@ -165,7 +210,7 @@ def formatted(self, n, unit=None): if self.thousands_separator: sep = u',' - fmt = u'{{:0{}.{:d}f}}'.format(sep, self.decimal_places) + fmt = u'{{:0{}.{:d}f}}'.format(sep, self._decimal_places(n)) num = fmt.format(n) # log.debug('n=%r, fmt=%r, num=%r', n, fmt, num) num = num.replace(',', '||comma||') @@ -436,27 +481,6 @@ def parse_units(self, query, qty=1): return from_unit, to_unit -def format_number(n): - """Format a floating point number with thousands/decimal separators. - - Args: - n (float): Number to format - - """ - sep = '' - if THOUSANDS_SEPARATOR: - sep = ',' - - fmt = '{{:0{}.{:d}f}}'.format(sep, DECIMAL_PLACES) - num = fmt.format(n) - # log.debug('n=%r, fmt=%r, num=%r', n, fmt, num) - num = num.replace(',', '||comma||') - num = num.replace('.', '||point||') - num = num.replace('||comma||', THOUSANDS_SEPARATOR) - num = num.replace('||point||', DECIMAL_SEPARATOR) - return num - - def register_units(): """Add built-in and user units to unit registry.""" # Add custom units from workflow and user data @@ -541,7 +565,8 @@ def convert(query): valid=False, icon=ICON_WARNING) else: # Show results - f = Formatter(DECIMAL_PLACES, DECIMAL_SEPARATOR, THOUSANDS_SEPARATOR) + f = Formatter(DECIMAL_PLACES, DECIMAL_SEPARATOR, THOUSANDS_SEPARATOR, + DYNAMIC_DECIMALS) wf.setvar('query', query) for conv in results: value = copytext = f.formatted(conv.to_number, conv.to_unit) diff --git a/src/info.plist b/src/info.plist index b41c563..273c7e7 100644 --- a/src/info.plist +++ b/src/info.plist @@ -503,6 +503,8 @@ DECIMAL_PLACES is the number of decimal places to show in conversion results. DECIMAL_SEPARATOR is the character used to separate whole numbers from decimal fraction when parsing and outputting numbers. +DYNAMIC_DECIMALS is whether to dynamically increase the number of decimal places shown until the result is non-zero. Set to 0 or empty to turn off. + THOUSANDS_SEPARATOR is the character used to separate thousands when parsing and outputting numbers. UPDATE_INTERVAL is the number of minutes between exchange rate updates. @@ -627,6 +629,8 @@ UPDATE_INTERVAL is the number of minutes between exchange rate updates. 2 DECIMAL_SEPARATOR . + DYNAMIC_DECIMALS + 1 THOUSANDS_SEPARATOR , UPDATE_INTERVAL @@ -637,7 +641,7 @@ UPDATE_INTERVAL is the number of minutes between exchange rate updates. APP_KEY version - 3.4 + 3.5 webaddress