diff options
| -rw-r--r-- | firefly_cli/config.py | 35 | ||||
| -rw-r--r-- | tests/unit/test_config.py | 35 |
2 files changed, 70 insertions, 0 deletions
diff --git a/firefly_cli/config.py b/firefly_cli/config.py new file mode 100644 index 0000000..eb1c460 --- /dev/null +++ b/firefly_cli/config.py @@ -0,0 +1,35 @@ +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> GPL-2.0-only +import os +import tomllib +from pathlib import Path +from firefly_cli.errors import ConfigError + +DEFAULT_PATH = Path(os.path.expanduser("~/.config/firefly-cli/config.toml")) + +def load(path=DEFAULT_PATH, env=None): + env = os.environ if env is None else env + url = env.get("FIREFLY_URL") + token = env.get("FIREFLY_TOKEN") + if not (url and token) and Path(path).exists(): + with open(path, "rb") as fh: + data = tomllib.load(fh) + url = url or data.get("url") + token = token or data.get("token") + if not url or not token: + raise ConfigError( + "No Firefly III config found. Run `firefly auth set` " + "or set FIREFLY_URL and FIREFLY_TOKEN." + ) + return {"url": url.rstrip("/"), "token": token} + +def write(url, token, path=DEFAULT_PATH): + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + # tomllib cannot write; template the 2-key file (deps stay at zero). + content = ( + f'url = "{url.rstrip("/")}"\n' + f'token = "{token}"\n' + ) + path.write_text(content) + path.chmod(0o600) + return path diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py new file mode 100644 index 0000000..de90a3b --- /dev/null +++ b/tests/unit/test_config.py @@ -0,0 +1,35 @@ +import os, tempfile, unittest +from pathlib import Path +from firefly_cli import config +from firefly_cli.errors import ConfigError + +class TestConfig(unittest.TestCase): + def setUp(self): + self.dir = tempfile.TemporaryDirectory() + self.path = Path(self.dir.name) / "config.toml" + def tearDown(self): + self.dir.cleanup() + for k in ("FIREFLY_URL", "FIREFLY_TOKEN"): + os.environ.pop(k, None) + + def test_write_then_read_roundtrip(self): + config.write("https://f.example/", "tok123", path=self.path) + cfg = config.load(path=self.path, env={}) + self.assertEqual(cfg["url"], "https://f.example") # trailing slash trimmed + self.assertEqual(cfg["token"], "tok123") + + def test_env_overrides_file(self): + config.write("https://file/", "filetok", path=self.path) + cfg = config.load(path=self.path, + env={"FIREFLY_URL": "https://env", "FIREFLY_TOKEN": "envtok"}) + self.assertEqual(cfg["url"], "https://env") + self.assertEqual(cfg["token"], "envtok") + + def test_missing_everything_raises_configerror(self): + with self.assertRaises(ConfigError): + config.load(path=self.path, env={}) + + def test_env_only_no_file(self): + cfg = config.load(path=self.path, + env={"FIREFLY_URL": "https://env/", "FIREFLY_TOKEN": "t"}) + self.assertEqual(cfg["url"], "https://env") |
