Repository: qtile/qtile

Issue:
Bitcoin Ticker keeps showing locale currency sign
My locale is GB, so if I don't specify a currency, it will show BTC in £. But when I specify, say,"USD", it shows the USD **numbers** but still shows the "£" sign in front of it.

So let's say BTC is "$44,000" in USD and "£31,000" in GBP. If I don't specify, it will say "£31,000". But if I write "USD", it says "**£**44,000" (the USD value, but the GBP sign).
Update Bitcoin ticker to handle other cryptocurrencies.
Redo of #2493. Fixes #2470.

~~Still needs a test.~~


Discussion:
Looking at the code, I don't think the symbol is connected to your chosen currency. As you say, it's just determined by your locale.

Would need some extra code to change the symbol too. Are you happy to have a go at submitting a pull request for this?
Yeah might be good to just add a text formatting option so users can stick in
whatever they want. It seems however that the symbol is found with
`locale.localeconv()['currency_symbol']`. For me this is `''` so... not helpful.

On 210518 03:28, elParaguayo wrote:
>Looking at the code, I don't think the symbol is connected to your chosen currency. As you say, it's just determined by your locale.
>
>Would need some extra code to change the symbol too. Are you happy to have a go at submitting a pull request for this?
>
>-- 
>You are receiving this because you are subscribed to this thread.
>Reply to this email directly or view it on GitHub:
>https://github.com/qtile/qtile/issues/2470#issuecomment-843053219

You could move the symbol to being configurable but have it default to the locale version (which should hopefully mean it doesn't break for people currently using it). It can then be overwritten as necessary.
Yeah, sounds good. If the default format matches what it currently results in
i.e. `"{symbol}{value}"` or something, then `symbol` could be what it gets from
the locale, and nothing changes for most people. If people are not getting what
they want they can change it manually to `"£{value}"` for example.

On 210518 03:50, elParaguayo wrote:
>You could move the symbol to being configurable but have it default to the locale version (which should hopefully mean it doesn't break for people currently using it). It can then be overwritten as necessary.
>
>-- 
>You are receiving this because you commented.
>Reply to this email directly or view it on GitHub:
>https://github.com/qtile/qtile/issues/2470#issuecomment-843066132

The widget hardcodes the display as `BTC: {symbol}{amount}`. We could pull that out into a configurable item as well (in case people want to change the prefix). Only issue with that is you've got two places where the symbol can be changed.
I think it's good that the general text format is configurable; this is what we
have for many other widgets. But I don't think we need `symbol` to be directly
configurable, because it'd be redundant like you said, as it can be set in the
format string. So rather than adding a `symbol` option (as the `{symbol}` in the
format string will always be from the locale), the string formatting option is
sufficient for setting non-locale symbols (but also for e.g. changing the
prefix).

On 210518 04:05, elParaguayo wrote:
>The widget hardcodes the display as `BTC: {symbol}{amount}`. We could pull that out into a configurable item as well (in case people want to change the prefix). Only issue with that is you've got two places where the symbol can be changed.
>
>-- 
>You are receiving this because you commented.
>Reply to this email directly or view it on GitHub:
>https://github.com/qtile/qtile/issues/2470#issuecomment-843075961

OK - it looks like that widget wasn't included in my batch of tests so I'm happy to make the changes and add a test while I'm at it.

@hamensman - thanks for reporting this.
Just saw this. Let me fit it in #2493.
Thanks for picking this up. I'd done changes to the widget but had a manic week last week and hadn't got round to doing the test.

When your PR gets merged, I'll write a test for it.


Resolving patch:
diff --git a/libqtile/scripts/migrate.py b/libqtile/scripts/migrate.py
--- a/libqtile/scripts/migrate.py
+++ b/libqtile/scripts/migrate.py
@@ -69,6 +69,14 @@ def pacman_to_checkupdates(query):
     )
 
 
+def bitcoin_to_crypto(query):
+    return (
+        query
+        .select_class("BitcoinTicker")
+        .rename("CryptoTicker")
+    )
+
+
 def hook_main_function(query):
     def modify_main(node, capture, filename):
         main = capture.get("function_def")
diff --git a/libqtile/widget/__init__.py b/libqtile/widget/__init__.py
--- a/libqtile/widget/__init__.py
+++ b/libqtile/widget/__init__.py
@@ -28,7 +28,6 @@
     "Backlight": "backlight",
     "Battery": "battery",
     "BatteryIcon": "battery",
-    "BitcoinTicker": "bitcoin_ticker",
     "Bluetooth": "bluetooth",
     "CPU": "cpu",
     "CPUGraph": "graph",
@@ -40,6 +39,7 @@
     "Clock": "clock",
     "Cmus": "cmus",
     "Countdown": "countdown",
+    "CryptoTicker": "crypto_ticker",
     "CurrentLayout": "currentlayout",
     "CurrentLayoutIcon": "currentlayout",
     "CurrentScreen": "currentscreen",
diff --git a/libqtile/widget/bitcoin_ticker.py b/libqtile/widget/crypto_ticker.py
similarity index 57%
rename from libqtile/widget/bitcoin_ticker.py
rename to libqtile/widget/crypto_ticker.py
--- a/libqtile/widget/bitcoin_ticker.py
+++ b/libqtile/widget/crypto_ticker.py
@@ -4,6 +4,7 @@
 # Copyright (c) 2014 Aborilov Pavel
 # Copyright (c) 2014 Sean Vig
 # Copyright (c) 2014-2015 Tycho Andersen
+# Copyright (c) 2021 Graeme Holliday
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -29,42 +30,61 @@
 from libqtile.widget.generic_poll_text import GenPollUrl
 
 _DEFAULT_CURRENCY = str(locale.localeconv()['int_curr_symbol'])
+_DEFAULT_SYMBOL = str(locale.localeconv()['currency_symbol'])
 
 
-class BitcoinTicker(GenPollUrl):
+class CryptoTicker(GenPollUrl):
     """
-    A bitcoin ticker widget, data provided by the coinbase.com API. Defaults to
-    displaying currency in whatever the current locale is. Examples::
+    A cryptocurrency ticker widget, data provided by the coinbase.com API. Defaults to
+    displaying currency in whatever the current locale is. Examples:
 
         # display the average price of bitcoin in local currency
-        widget.BitcoinTicker()
+        widget.CryptoTicker()
 
         # display it in Euros:
-        widget.BitcoinTicker(currency="EUR")
+        widget.CryptoTicker(currency="EUR")
+
+        # or a different cryptocurrency!
+        widget.CryptoTicker(crypto="ETH")
+
+        # change the currency symbol:
+        widget.CryptoTicker(currency="EUR", symbol="€")
     """
 
-    QUERY_URL = "https://api.coinbase.com/v2/prices/spot?currency=%s"
+    QUERY_URL = "https://api.coinbase.com/v2/prices/{}-{}/spot"
 
     orientations = base.ORIENTATION_HORIZONTAL
 
     defaults = [
         ('currency', _DEFAULT_CURRENCY.strip(),
-            'The currency the value that bitcoin is displayed in'),
+            'The baseline currency that the value of the crypto is displayed in.'),
+        ('symbol', _DEFAULT_SYMBOL,
+            'The symbol for the baseline currency.'),
+        ('crypto', 'BTC',
+            'The cryptocurrency to display.'),
+        ('format', '{crypto}: {symbol}{amount:.2f}',
+            'Display string formatting.'),
     ]
 
     def __init__(self, **config):
         GenPollUrl.__init__(self, **config)
-        self.add_defaults(BitcoinTicker.defaults)
+        self.add_defaults(CryptoTicker.defaults)
 
-        # set up USD as the default if no locale is set
+        # set up USD as the currency if no locale is set
         if self.currency == "":
-            locale.setlocale(locale.LC_MONETARY, "en_US.UTF-8")
-            self.currency = locale.localeconv()['int_curr_symbol'].strip()
-        self.symbol = locale.localeconv()['currency_symbol']
+            self.currency = 'USD'
+        # set up $ as the symbol if no locale is set
+        if self.symbol == "":
+            self.symbol = '$'
 
     @property
     def url(self):
-        return self.QUERY_URL % self.currency.lower()
+        return self.QUERY_URL.format(self.crypto, self.currency)
 
     def parse(self, body):
-        return "BTC: {symbol}{amount}".format(symbol=self.symbol, amount=body['data']['amount'])
+        variables = dict()
+        variables['crypto'] = self.crypto
+        variables['symbol'] = self.symbol
+        variables['amount'] = float(body['data']['amount'])
+
+        return self.format.format(**variables)


Test patch: