Skip to content

Commit

Permalink
feat: Read config from XDG_CONFIG_HOME or custom path (#77)
Browse files Browse the repository at this point in the history
* read config from XDG_CONFIG_HOME or custom path

* v1.5.0

* test custom config path parsing

* test default/custom XDG_CONFIG_HOME values
  • Loading branch information
chadsr authored May 26, 2024
1 parent 4e5ee4e commit 426846c
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 61 deletions.
94 changes: 39 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,25 @@ A [Waybar](https://github.com/Alexays/Waybar) module for displaying cryptocurren

## Requirements

- `python` >=3.8
- `python` >=3.9
- `python-requests`

## Installation

### Clone to the Waybar modules directory
### AUR

```shell
yay -S waybar-crypto
```

**Note:** *For the time being, the `cryptofont` font still needs installing manually*

### (Or) Clone to the Waybar modules directory

```shell
cd ~/.config/waybar/modules
git clone https://github.com/chadsr/waybar-crypto.git crypto && cd crypto/
git submodule update --init --recursive --remote --progress

# **only** If you for some reason don't want to install python-requests with a package manager, or setup a venv
pip install --user --requirement <(poetry export --without=dev --format requirements.txt)
```

### Install the needed fonts
Expand All @@ -36,7 +41,14 @@ ln -s ./.submodules/cryptofont/fonts/cryptofont.ttf ~/.local/share/fonts/TTF
fc-cache -f
```

### Update Waybar configuration
### Create Configuration File

Create a configuration file at `$XDG_CONFIG_HOME/waybar-crypto/config.ini` (This location can be customised with the `--config-path` flag). The module **will not** run without first creating this configuration file.

An example can be found in [`config.ini.example`](./config.ini.example) with further options described below in the [Configuration](#configuration) section.


### Update Waybar Configuration

*Found at `~/.config/waybar/config` by default*

Expand All @@ -45,7 +57,7 @@ fc-cache -f
"format": "{}",
"interval": 600,
"return-type": "json",
"exec": "~/.config/waybar/modules/crypto/waybar_crypto.py",
"exec": "waybar-crypto", // change this if you installed manually
"exec-if": "ping pro-api.coinmarketcap.com -c1"
}
```
Expand All @@ -56,66 +68,38 @@ fc-cache -f

```css
#custom-crypto {
font-family: cryptofont, monospace;
font-family: cryptofont;
}
```

## Configuration

Copy the example configuration file `config.ini.example` to `config.ini`.

The information displayed can then be customised by editing the `config.ini` configuration file.
(e.g. `~/.config/waybar/modules/crypto/config.ini` if you followed the instructions above)

```ini
[general]
currency = eur
currency_symbol = €
spacer_symbol = |
display = price,percent_change_24h,percent_change_7d
api_key = your_coinmarketcap_api_key

[btc]
icon = 
in_tooltip = false
price_precision = 2
change_precision = 2
volume_precision = 2

[eth]
icon = 
in_tooltip = true
price_precision = 2
change_precision = 2
volume_precision = 2
```

- **currency:** Any valid currency code should be accepted
- **currency:** A valid currency code
- **currency_symbol:** A corresponding symbol of the currency you wish to display
- **spacer_symbol:** A string/character to use as a spacer between tickers. Comment out to disable.
- **api_key:** CoinmarketCap API key obtained from their [API Dashboard](https://coinmarketcap.com/api).
- **spacer_symbol:** A string/character to use as a spacer between tickers. Comment out to disable
- **display:** A list of metrics you wish to display for each crypto currency. No spaces.
Valid options are:
- **price:** Displays the current price.
- **percent_change_1h:** Price change over the past hour.
- **percent_change_24h:** Price change over the past 24 hours.
- **percent_change_7d:** Price change over the past week.
- **percent_change_30d:** Price change over the past thirty days.
- **percent_change_60d:** Price change over the past sixty days.
- **percent_change_90d:** Price change over the past ninety days.
- **volume_24h:** Market volume in your chosen currency, over the past 24 hours.
- **volume_change_24h:** Market volume change in your chosen currency, over the past 24 hours.

*Alternatively, the CoinMarketCap API key can be set through the environment variable `COINMARKETCAP_API_KEY`, if you do not wish to save it to the `config.ini` configuration file.*
- **price:** current price
- **percent_change_1h:** Price change over the past hour
- **percent_change_24h:** Price change over the past 24 hours
- **percent_change_7d:** Price change over the past week
- **percent_change_30d:** Price change over the past thirty days
- **percent_change_60d:** Price change over the past sixty days
- **percent_change_90d:** Price change over the past ninety days
- **volume_24h:** Market volume in your chosen currency, over the past 24 hours
- **volume_change_24h:** Market volume change in your chosen currency, over the past 24 hours
- **api_key:** CoinmarketCap API key obtained from their [API Dashboard](https://coinmarketcap.com/api)

*Alternatively, the CoinMarketCap API key can be set through the environment variable `COINMARKETCAP_API_KEY`, if you do not wish to save it to the `config.ini` configuration file.*

### Adding Cryptocurrencies

For each cryptocurrency you wish to display, add a section as shown in the example above, where the section name is the **short** cryptocurrency name as found on [CoinMarketCap](https://coinmarketcap.com/).

Valid options:

- **icon:** A character symbol to display next to this cryptocurrency's metrics.
- **in_tooltip:** Whether to display the data in the tooltip instead of the bar (defaults to false).
- **price_precision** The decimal precision at which to display the price value of the cryptocurrency.
- **change_precision** The decimal precision at which to display the change value(s) of the cryptocurrency.
- **volume_precision** The decimal precision at which to display the volume value of the cryptocurrency.
- **icon:** A character symbol to display next to this cryptocurrency's metrics
- **in_tooltip:** Whether to display the data in the tooltip instead of the bar (defaults to false)
- **price_precision** The decimal precision at which to display the price value of the cryptocurrency
- **change_precision** The decimal precision at which to display the change value(s) of the cryptocurrency
- **volume_precision** The decimal precision at which to display the volume value of the cryptocurrency
1 change: 1 addition & 0 deletions config.ini.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ currency_symbol = €
display = price,percent_change_24h
spacer_symbol = |
api_key = your_coinmarketcap_api_key
; COINMARKETCAP_API_KEY env variable can alternatively be used and will take precedence

[btc]
icon = 
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "waybar-crypto"
version = "v1.4.0"
version = "v1.5.0"
description = "A Waybar module for displaying cryptocurrency market information from CoinMarketCap."
authors = ["Ross <[email protected]>"]
license = "MIT"
Expand Down
40 changes: 39 additions & 1 deletion tests/test_waybar_crypto.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import os
import argparse
import pytest
from unittest import mock

from waybar_crypto import CLASS_NAME, ResponseQuotesLatest, WaybarCrypto
from waybar_crypto import (
CLASS_NAME,
DEFAULT_XDG_CONFIG_HOME_PATH,
XDG_CONFIG_HOME_ENV,
ResponseQuotesLatest,
WaybarCrypto,
parse_args,
)


# Get the absolute path of this script
ABS_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG_PATH = f"{ABS_DIR}/../config.ini.example"
TEST_CONFIG_PATH = "/test_path"


@pytest.fixture()
Expand Down Expand Up @@ -87,6 +97,34 @@ def quotes_latest():
}


def test_parse_args_default_path():
with mock.patch("sys.argv", ["waybar_crypto.py"]):
os.environ[XDG_CONFIG_HOME_ENV] = ""
args = parse_args()
assert "config_path" in args
assert os.path.expanduser(DEFAULT_XDG_CONFIG_HOME_PATH) in os.path.expanduser(
args["config_path"]
)


def test_parse_args_custom_xdg_data_home():
with mock.patch("sys.argv", ["waybar_crypto.py"]):
os.environ[XDG_CONFIG_HOME_ENV] = TEST_CONFIG_PATH
args = parse_args()
assert "config_path" in args
assert TEST_CONFIG_PATH in args["config_path"]


@mock.patch(
"argparse.ArgumentParser.parse_args",
return_value=argparse.Namespace(config_path=TEST_CONFIG_PATH),
)
def test_parse_args_custom_path(mock: mock.MagicMock):
args = parse_args()
assert "config_path" in args
assert args["config_path"] == TEST_CONFIG_PATH


class TestWaybarCrypto:
"""Tests for the WaybarCrypto."""

Expand Down
40 changes: 36 additions & 4 deletions waybar_crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
import requests
import json
import configparser
import argparse

API_URL = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest"
API_KEY_ENV = "COINMARKETCAP_API_KEY"

XDG_CONFIG_HOME_ENV = "XDG_CONFIG_HOME"
DEFAULT_XDG_CONFIG_HOME_PATH = "~/.config"
CONFIG_DIR = "waybar-crypto"
CONFIG_FILE = "config.ini"

DEFAULT_PRECISION = 2
Expand Down Expand Up @@ -43,6 +48,10 @@
TIMEOUT_SECONDS = 10


class Args(TypedDict):
config_path: str


class ConfigGeneral(TypedDict):
currency: str
currency_symbol: str
Expand Down Expand Up @@ -313,12 +322,35 @@ def waybar_output(self, quotes_latest: ResponseQuotesLatest) -> WaybarOutput:
return output_obj


def parse_args() -> Args:
parser = argparse.ArgumentParser()

# Utilise XDG_CONFIG_HOME if it exists
xdg_config_home_path = os.getenv(XDG_CONFIG_HOME_ENV)
if not xdg_config_home_path:
xdg_config_home_path = DEFAULT_XDG_CONFIG_HOME_PATH

default_config_path = os.path.join(xdg_config_home_path, CONFIG_DIR, CONFIG_FILE)
parser.add_argument(
"-c",
"--config-path",
type=str,
default=default_config_path,
help=f"Path to the configuration file (default: '{default_config_path}')",
)
args = parser.parse_args()

return {"config_path": args.config_path}


def main():
# Get the absolute path of this script
abs_dir = os.path.dirname(os.path.abspath(__file__))
config_path = f"{abs_dir}/{CONFIG_FILE}"
args = parse_args()

config_path = args["config_path"]
if not os.path.isfile(config_path):
raise WaybarCryptoException(f"configuration file not found at '{config_path}'")

waybar_crypto = WaybarCrypto(config_path)
waybar_crypto = WaybarCrypto(args["config_path"])
quotes_latest = waybar_crypto.coinmarketcap_latest()
output = waybar_crypto.waybar_output(quotes_latest)

Expand Down

0 comments on commit 426846c

Please sign in to comment.