From 69d471a8599b6c791958aa4ebfa8170d0b64d4e7 Mon Sep 17 00:00:00 2001 From: 3wc <3wc@doesthisthing.work> Date: Wed, 6 Aug 2025 11:07:45 +0100 Subject: [PATCH] Working config loading from TOML, env var, cli args --- hamstertools/__init__.py | 36 ++++++++++++++++++------------------ hamstertools/app.py | 12 ++---------- hamstertools/kimaiapi.py | 14 +++++--------- hamstertools/sync.py | 4 +--- 4 files changed, 26 insertions(+), 40 deletions(-) diff --git a/hamstertools/__init__.py b/hamstertools/__init__.py index cccd688..aa17f1d 100755 --- a/hamstertools/__init__.py +++ b/hamstertools/__init__.py @@ -42,14 +42,15 @@ db.init(HAMSTER_FILE) @click.group(context_settings={"auto_envvar_prefix": "HAMSTERTOOL"}) @click.option("-d", "--debug", is_flag=True) @click.option("--config", default=CONFIG_FILE, type=click.Path()) -@click.option("--kimai-api-key", envvar="KIMAI_API_KEY") +@click.option("--kimai-api-url", envvar="KIMAI_API_URL") @click.option("--kimai-username", envvar="KIMAI_USERNAME") @click.option("--kimai-api-key", envvar="KIMAI_API_KEY") @click.pass_context -def cli(ctx, config, debug, kimai_api_url, kimai_username, kimai_api_key): +def cli(ctx, config, debug, kimai_api_url=None, kimai_username=None, kimai_api_key=None): + file_config = {} if os.path.exists(config): with open(config, "rb") as f: - ctx.default_map = tomllib.load(f) + file_config = tomllib.load(f) if debug: logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) @@ -62,6 +63,12 @@ def cli(ctx, config, debug, kimai_api_url, kimai_username, kimai_api_key): requests_log.setLevel(logging.DEBUG) requests_log.propagate = True + ctx.obj = KimaiAPI( + kimai_username if kimai_username is not None else file_config.get("kimai_username"), + kimai_api_key if kimai_api_key is not None else file_config.get("kimai_api_key"), + kimai_api_url if kimai_api_url is not None else file_config.get("kimai_api_url"), + ) + @cli.group() def categories(): @@ -326,12 +333,8 @@ def find_duplicates(): @cli.group() -@click.pass_context -def kimai(ctx, kimai_username=None, kimai_api_key=None): - ctx.ensure_object(dict) - - ctx.obj['KIMAI_USERNAME'] = kimai_username - ctx.obj['KIMAI_API_KEY'] = kimai_api_key +def kimai(): + pass def _get_kimai_mapping_file(path, category_search=None): @@ -776,11 +779,10 @@ def reset(): @db_.command("sync") -@click.pass_context -def kimai_db_sync(ctx): +@click.pass_obj +def kimai_db_sync(api): sync( - username=ctx.obj['KIMAI_USERNAME'], - api_key=ctx.obj['KIMAI_API_KEY'] + api ) @@ -822,14 +824,12 @@ def mapping2db(mapping_path=None, global_=False): @cli.command() -@click.pass_context -def app(ctx): +@click.pass_obj +def app(kimai_api): from .app import HamsterToolsApp app = HamsterToolsApp( - kimai_api_url=ctx.obj["KIMAI_API_URL"], - kimai_username=ctx.obj["KIMAI_USERNAME"], - kimai_api_key=ctx.obj["KIMAI_API_KEY"] + kimai_api ) app.run() diff --git a/hamstertools/app.py b/hamstertools/app.py index 5c00d33..2f4ff15 100644 --- a/hamstertools/app.py +++ b/hamstertools/app.py @@ -16,22 +16,14 @@ class HamsterToolsApp(App): ("q", "quit", "Quit"), ] - api_ = None - - @property - def api(self) -> KimaiAPI: - if self.api_ is None: - self.api_ = KimaiAPI(self.kimai_api_key) - return self.api_ - - def __init__(self, kimai_api_key): - self.kimai_api_key = kimai_api_key + def __init__(self, kimai_api=None): self.add_mode("hamster", HamsterScreen()) self.add_mode("kimai", KimaiScreen()) # self.mode MODES = { # "hamster": HamsterScreen(), # "kimai": KimaiScreen(), # } + self.api = kimai_api super().__init__() diff --git a/hamstertools/kimaiapi.py b/hamstertools/kimaiapi.py index 3f258fb..43276db 100644 --- a/hamstertools/kimaiapi.py +++ b/hamstertools/kimaiapi.py @@ -1,7 +1,5 @@ from datetime import datetime import requests -import requests_cache -import os from dataclasses import dataclass, field @@ -11,14 +9,12 @@ class NotFound(Exception): class KimaiAPI(object): - # temporary hardcoded config - KIMAI_API_URL = "https://kimai.autonomic.zone/api" - # KIMAI_API_URL = "https://kimaitest.autonomic.zone/api" - - def __init__(self, username=None, api_key=None): + def __init__(self, username=None, api_key=None, api_url=None): self.auth_headers = {"X-AUTH-USER": username, "X-AUTH-TOKEN": api_key} + self.kimai_api_url = api_url # NOTE: Uncomment the following line to enable requests_cache, which can make development a *lot* faster # TODO: Add a config option or something for this + # import requests_cache # requests_cache.install_cache("kimai", backend="sqlite", expire_after=1800) self.customers_json = self.get("customers", {"visible": 3}) self.projects_json = self.get("projects", {"visible": 3, "ignoreDates": 1}) @@ -27,7 +23,7 @@ class KimaiAPI(object): def get(self, endpoint, params=None): result = requests.get( - f"{self.KIMAI_API_URL}/{endpoint}", params=params, headers=self.auth_headers + f"{self.kimai_api_url}/{endpoint}", params=params, headers=self.auth_headers ).json() try: if result["code"] != 200: @@ -38,7 +34,7 @@ class KimaiAPI(object): def post(self, endpoint, data): return requests.post( - f"{self.KIMAI_API_URL}/{endpoint}", json=data, headers=self.auth_headers + f"{self.kimai_api_url}/{endpoint}", json=data, headers=self.auth_headers ) diff --git a/hamstertools/sync.py b/hamstertools/sync.py index d8f2080..1089ee2 100644 --- a/hamstertools/sync.py +++ b/hamstertools/sync.py @@ -12,9 +12,7 @@ from .db import ( ) -def sync(username, api_key) -> None: - api = KimaiAPI(username, api_key) - +def sync(api) -> None: KimaiCustomer.delete().execute() KimaiProject.delete().execute() KimaiActivity.delete().execute()