From b0a71e804dbcb4833f551b5d09c69ff19087131f Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 22 Apr 2025 18:08:42 +0200 Subject: [PATCH 1/2] fix: Ensure uv lock file points to correct version --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index 13bd029..c03569d 100644 --- a/uv.lock +++ b/uv.lock @@ -73,7 +73,7 @@ sdist = { url = "https://files.pythonhosted.org/packages/3e/50/3e876f39e31bad878 [[package]] name = "topen" -version = "0.1.0" +version = "0.2.0" source = { editable = "." } dependencies = [ { name = "tasklib" }, From 7dbd93796d7de7812223d3cc7f375ca0ae3c8a51 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 22 Apr 2025 21:49:24 +0200 Subject: [PATCH 2/2] ref: Remove property setters from dataclass Removed the property setters and getters from variables with complex defaults. Instead, they are now given a specific const default value `Path("%%%%I_DONT_EXIST_%%%%")` which is very unlikely to be used by a user in normal circumstances. This is necessary to be able to remove the properties since Python does not distinguish between an empty Path() and a non-given Path() (i.e. there is no Path value which returns Falsy). However, this slightly clunky construct does allow setting the various Paths once and only once, and also to remove all the previously necessary getters and setters with their hidden backing variables. Lastly it should open the gates for changing the _real_path transformation to be part of the TConf class itself and not a global function. --- CHANGELOG.md | 4 ++++ topen.py | 54 ++++++++++++++++++++-------------------------------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea00713..dee7329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Default paths are only calculated once, though users can now not use specifically '%%%%I_DONT_EXIST_%%%%' as a path for the taskrc file and task data directory. + ## [0.2.0] - 2025-04-09 ### Added diff --git a/topen.py b/topen.py index 274b84f..7585d5a 100755 --- a/topen.py +++ b/topen.py @@ -22,12 +22,14 @@ import os import subprocess import sys from collections import namedtuple -from dataclasses import asdict, dataclass, field +from dataclasses import asdict, dataclass from pathlib import Path -from typing import Any, Self, cast +from typing import Any, Self from tasklib import Task, TaskWarrior +NON_EXISTENT_PATH = Path("%%%%I_DONT_EXIST_%%%%") + def main(): """Runs the cli interface. @@ -118,43 +120,14 @@ class TConf: task_id: int """The id (or uuid) of the task to edit a note for.""" - task_rc: Path - _task_rc: Path | None = field(init=False, repr=False, default=None) + task_rc: Path = NON_EXISTENT_PATH """The path to the taskwarrior taskrc file. Can be absolute or relative to cwd.""" - @property - def task_rc(self) -> Path: - if self._task_rc: - return self._task_rc - elif _real_path("~/.taskrc").exists(): - return _real_path("~/.taskrc") - elif _real_path("$XDG_CONFIG_HOME/task/taskrc").exists(): - return _real_path("$XDG_CONFIG_HOME/task/taskrc") - else: - return _real_path("~/.config/task/taskrc") - - @task_rc.setter - def task_rc(self, value: Path | property | None): - if type(value) is property: - value = TConf._notes_dir - self._task_rc = cast(Path, value) - task_data: Path = Path("~/.task") """The path to the taskwarrior data directory. Can be absolute or relative to cwd.""" - notes_dir: Path + notes_dir: Path = NON_EXISTENT_PATH """The path to the notes directory.""" - _notes_dir: Path | None = field(init=False, repr=False, default=None) - - @property - def notes_dir(self) -> Path: - return self._notes_dir if self._notes_dir else self.task_data.joinpath("notes") - - @notes_dir.setter - def notes_dir(self, value: Path | property | None): - if type(value) is property: - value = TConf._notes_dir - self._notes_dir = cast(Path, value) notes_ext: str = "md" """The extension of note files.""" @@ -166,13 +139,28 @@ class TConf: """If set topen will give no feedback on note editing.""" def __post_init__(self): + if self.task_rc == NON_EXISTENT_PATH: + self.task_rc = self._default_task_rc() self.task_rc = _real_path(self.task_rc) self.task_data = _real_path(self.task_data) + if self.notes_dir == NON_EXISTENT_PATH: + self.notes_dir = self._default_notes_dir() self.notes_dir = _real_path(self.notes_dir) def __or__(self, other: Any, /) -> Self: return self.__class__(**asdict(self) | asdict(other)) + def _default_task_rc(self) -> Path: + if Path("~/.taskrc").exists(): + return Path("~/.taskrc") + elif Path("$XDG_CONFIG_HOME/task/taskrc").exists(): + return Path("$XDG_CONFIG_HOME/task/taskrc") + else: + return Path("~/.config/task/taskrc") + + def _default_notes_dir(self) -> Path: + return self.task_data.joinpath("notes") + @classmethod def from_dict(cls, d: dict) -> Self: """Generate a TConf class from a dictionary.