ref: Remove property setters from dataclass
Some checks failed
website / deploy (push) Has been cancelled
website / build (push) Has been cancelled

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.
This commit is contained in:
Marty Oehme 2025-04-22 21:49:24 +02:00
parent b0a71e804d
commit 7dbd93796d
Signed by: Marty
GPG key ID: 4E535BC19C61886E
2 changed files with 25 additions and 33 deletions

View file

@ -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

View file

@ -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.