From 1c3867f5c0fc92db4f87f1477eb36946588e2db3 Mon Sep 17 00:00:00 2001 From: Gabriel Fontes Date: Wed, 6 May 2026 11:51:58 -0300 Subject: [PATCH] chore(lock): bump nixpkgs --- flake.lock | 6 +- overlays/default.nix | 3 +- overlays/todoman-latest-main.patch | 1089 ---------------------------- overlays/todoman-subtasks.patch | 375 +++++----- 4 files changed, 202 insertions(+), 1271 deletions(-) delete mode 100644 overlays/todoman-latest-main.patch diff --git a/flake.lock b/flake.lock index 4c66acab..9e666ea0 100644 --- a/flake.lock +++ b/flake.lock @@ -450,11 +450,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1777563220, - "narHash": "sha256-xnZag8NkDjmZS/ljX+d7y+ybJqJ8mwoKRDft7JCTgHk=", + "lastModified": 1777954456, + "narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "42a92b2b1f0d79b337dc9e1121f375b68b97ebd3", + "rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1", "type": "github" }, "original": { diff --git a/overlays/default.nix b/overlays/default.nix index 6b1a478b..04354e5d 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -62,9 +62,8 @@ in { vdirsyncer = addPatches prev.vdirsyncer [./vdirsyncer-fixed-oauth-token.patch]; - # https://github.com/pimutils/todoman/pull/594 todoman = addPatches prev.todoman [ - ./todoman-latest-main.patch + # https://github.com/pimutils/todoman/pull/594 ./todoman-subtasks.patch ./todoman-disable-uid-hostname-suffix.diff ]; diff --git a/overlays/todoman-latest-main.patch b/overlays/todoman-latest-main.patch deleted file mode 100644 index 853c4aef..00000000 --- a/overlays/todoman-latest-main.patch +++ /dev/null @@ -1,1089 +0,0 @@ -From 4b704244e5345ce302d9bada6ff3300eadf10547 Mon Sep 17 00:00:00 2001 -From: Sardorbek Imomaliev -Date: Sun, 20 Jul 2025 19:50:17 +0100 -Subject: [PATCH 01/18] :show-nested: is deprecated - -Read more https://sphinx-click.readthedocs.io/en/latest/usage/#usage -> This option is deprecated; use nested instead. ---- - docs/source/man.rst | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/docs/source/man.rst b/docs/source/man.rst -index 467a9043..06e3e2a7 100644 ---- a/docs/source/man.rst -+++ b/docs/source/man.rst -@@ -3,7 +3,7 @@ Man page - - .. click:: todoman.cli:cli - :prog: todo -- :show-nested: -+ :nested: short - - Description - ----------- - -From 03ba2ce0521e6a6fe22cbbfd8ba2c7b6186e3c57 Mon Sep 17 00:00:00 2001 -From: Sardorbek Imomaliev -Date: Sun, 20 Jul 2025 20:02:45 +0100 -Subject: [PATCH 02/18] Move content from usage.rst and configure.rst to - separate files - -This is required to fix duplicated toctree elements due to inclusion of -usage.rst and configure.rst in man.rst. Now man.rst includes content -only. ---- - docs/source/_configure.rst | 47 +++++++++++++++ - docs/source/_usage.rst | 115 +++++++++++++++++++++++++++++++++++++ - docs/source/configure.rst | 45 +-------------- - docs/source/man.rst | 4 +- - docs/source/usage.rst | 113 +----------------------------------- - 5 files changed, 166 insertions(+), 158 deletions(-) - create mode 100644 docs/source/_configure.rst - create mode 100644 docs/source/_usage.rst - -diff --git a/docs/source/_configure.rst b/docs/source/_configure.rst -new file mode 100644 -index 00000000..7b5b0f16 ---- /dev/null -+++ b/docs/source/_configure.rst -@@ -0,0 +1,47 @@ -+Configuring -+=========== -+ -+You'll need to configure Todoman before the first usage, using its simple -+ini-like configuration file. -+ -+Configuration File -+------------------ -+ -+The configuration file should be placed in -+``$XDG_CONFIG_HOME/todoman/config.py``. ``$XDG_CONFIG_HOME`` defaults to -+``~/.config`` is most situations, so this will generally be -+``~/.config/todoman/config.py``. -+ -+.. include:: confspec.tmp -+ -+Sample configuration -+-------------------- -+ -+The below example should serve as a reference. It will read ics files from any -+directory inside ``~/.local/share/calendars/``, uses the ISO-8601 date format, -+and set the due date for new todos in 48hs. -+ -+.. literalinclude:: ../../config.py.sample -+ :language: python -+ -+Color and displayname -+--------------------- -+ -+- You can set a color for each task list by creating a ``color`` file containing -+ a color code in the hex format: ``#RRGGBB``. -+- A file named ``displayname`` indicates how the task list should be named and -+ is needed when there are multiple directories sharing a name, e.g.: when using -+ multiple $CloudInstances. The default is the directory name. -+ -+See also `relevant documentation for the vdir format -+`_. -+ -+Timezone -+-------- -+ -+Todoman will use the system-wide configured timezone. If this doesn't work for -+you, you _may_ override the timezone by specifying the ``TZ`` environment -+variable. -+ -+For instruction on changing your system's timezone, consult your distribution's -+documentation. -diff --git a/docs/source/_usage.rst b/docs/source/_usage.rst -new file mode 100644 -index 00000000..ac7ff6d0 ---- /dev/null -+++ b/docs/source/_usage.rst -@@ -0,0 +1,115 @@ -+Usage -+===== -+ -+Todoman usage is `CLI`_ based (thought there are some TUI bits, and the -+intentions is to also provide a fully `TUI`_-based interface). -+ -+The default action is ``list``, which outputs all tasks for all calendars, each -+with a semi-permanent unique id:: -+ -+ 1 [ ] !!! 2015-04-30 Close bank account @work (0%) -+ 2 [ ] ! Send minipimer back for warranty replacement @home (0%) -+ 3 [X] 2015-03-29 Buy soy milk @home (100%) -+ 4 [ ] !! Fix the iPad's screen @home (0%) -+ 5 [ ] !! Fix the Touchpad battery @work (0%) -+ -+The columns, in order, are: -+ -+ * An id. -+ * Whether the task has been completed or not. -+ * An ``!!!`` indicating high priority, ``!!`` indicating medium priority, -+ ``!`` indicating low priority tasks. -+ * The due date. -+ * The task summary. -+ * The list the todo is from; it will be hidden when filtering by one list, or -+ if the database only contains a single list. -+ * The completed percentage. -+ -+The id is retained by ``todoman`` until the next time you run the ``flush`` -+command. -+ -+To operate on a todo, the id is what's used to reference it. For example, to -+edit the `Buy soy milk` task from the example above, the proper command is -+``todo edit 3``, or ``todo undo 3`` to un-mark the task as done. -+ -+Editing tasks can only be done via the TUI interface for now, and cannot be -+done via the command line yet. -+ -+.. _cli: https://en.wikipedia.org/wiki/Command-line_interface -+.. _tui: https://en.wikipedia.org/wiki/Text-based_user_interface -+ -+ -+Synchronization -+--------------- -+ -+If you want to synchronize your tasks, you'll need something that syncs via -+CalDAV. `vdirsyncer`_ is the recommended tool for this. -+ -+.. _vdirsyncer: https://vdirsyncer.readthedocs.org/en/stable/ -+ -+Interactive shell -+----------------- -+ -+If you install `click-repl `_, todoman -+gets a new command called ``repl``, which launches an interactive shell with -+tab-completion. -+ -+Integrations -+------------ -+ -+When attempting to integrate ``todoman`` into other systems or parse its -+output, you're advised to use the ``--porcelain`` flag, which will print all -+output in a pre-defined format that will remain stable regardless of user -+configuration or version. -+ -+The format is JSON, with a single array containing each todo as a single entry -+(object). Fields will always be present; if a todo does not have a value for a -+given field, it will be printed as ``null``. -+ -+Fields MAY be added in future, but will never be removed. -+ -+Conky -+````` -+ -+Todoman can be used with `Conky`_ by using one of the shell execution -+`variables`_. -+Given the nature of pimutils utilities, there is no need to query new information -+every time conky updates so ``execi`` will be the best option most of the time. -+ -+Adding ``${execi 30 todo}`` inside the text section will display the output of the -+command and update it every 30 seconds. -+ -+A working configuration can be found `here`_. -+ -+.. _conky: https://conky.cc -+.. _variables: https://conky.sourceforge.net/variables.html -+.. _here: https://github.com/r4ulill0/todoman/blob/main/docs/examples/conky.conf -+ -+Sorting -+------- -+ -+The tasks can be sorted with the ``--sort`` argument. Sorting may be done according to the following fields: -+ -+ - ``description`` -+ - ``location`` -+ - ``status`` -+ - ``summary`` -+ - ``uid`` -+ - ``rrule`` -+ - ``percent_complete`` -+ - ``priority`` -+ - ``sequence`` -+ - ``categories`` -+ - ``completed_at`` -+ - ``created_at`` -+ - ``dtstamp`` -+ - ``start`` -+ - ``due`` -+ - ``last_modified`` -+ -+It is possible to prepend a ``-`` to a field to sort by that field in ascending -+order (by default they are sorted in descending order). -+ -+Example:: -+ -+ todo list --sort due,-priority -diff --git a/docs/source/configure.rst b/docs/source/configure.rst -index 7b5b0f16..37f852c4 100644 ---- a/docs/source/configure.rst -+++ b/docs/source/configure.rst -@@ -1,47 +1,4 @@ - Configuring - =========== - --You'll need to configure Todoman before the first usage, using its simple --ini-like configuration file. -- --Configuration File -------------------- -- --The configuration file should be placed in --``$XDG_CONFIG_HOME/todoman/config.py``. ``$XDG_CONFIG_HOME`` defaults to --``~/.config`` is most situations, so this will generally be --``~/.config/todoman/config.py``. -- --.. include:: confspec.tmp -- --Sample configuration ---------------------- -- --The below example should serve as a reference. It will read ics files from any --directory inside ``~/.local/share/calendars/``, uses the ISO-8601 date format, --and set the due date for new todos in 48hs. -- --.. literalinclude:: ../../config.py.sample -- :language: python -- --Color and displayname ----------------------- -- --- You can set a color for each task list by creating a ``color`` file containing -- a color code in the hex format: ``#RRGGBB``. --- A file named ``displayname`` indicates how the task list should be named and -- is needed when there are multiple directories sharing a name, e.g.: when using -- multiple $CloudInstances. The default is the directory name. -- --See also `relevant documentation for the vdir format --`_. -- --Timezone ---------- -- --Todoman will use the system-wide configured timezone. If this doesn't work for --you, you _may_ override the timezone by specifying the ``TZ`` environment --variable. -- --For instruction on changing your system's timezone, consult your distribution's --documentation. -+.. include:: _configure.rst -diff --git a/docs/source/man.rst b/docs/source/man.rst -index 06e3e2a7..26a96219 100644 ---- a/docs/source/man.rst -+++ b/docs/source/man.rst -@@ -15,12 +15,12 @@ using, for example, *vdirsyncer*. - Usage - ----- - --.. include:: usage.rst -+.. include:: _usage.rst - - Configuring - ----------- - --.. include:: configure.rst -+.. include:: _configure.rst - - Caveats - ------- -diff --git a/docs/source/usage.rst b/docs/source/usage.rst -index ac7ff6d0..1e84fd2b 100644 ---- a/docs/source/usage.rst -+++ b/docs/source/usage.rst -@@ -1,115 +1,4 @@ - Usage - ===== - --Todoman usage is `CLI`_ based (thought there are some TUI bits, and the --intentions is to also provide a fully `TUI`_-based interface). -- --The default action is ``list``, which outputs all tasks for all calendars, each --with a semi-permanent unique id:: -- -- 1 [ ] !!! 2015-04-30 Close bank account @work (0%) -- 2 [ ] ! Send minipimer back for warranty replacement @home (0%) -- 3 [X] 2015-03-29 Buy soy milk @home (100%) -- 4 [ ] !! Fix the iPad's screen @home (0%) -- 5 [ ] !! Fix the Touchpad battery @work (0%) -- --The columns, in order, are: -- -- * An id. -- * Whether the task has been completed or not. -- * An ``!!!`` indicating high priority, ``!!`` indicating medium priority, -- ``!`` indicating low priority tasks. -- * The due date. -- * The task summary. -- * The list the todo is from; it will be hidden when filtering by one list, or -- if the database only contains a single list. -- * The completed percentage. -- --The id is retained by ``todoman`` until the next time you run the ``flush`` --command. -- --To operate on a todo, the id is what's used to reference it. For example, to --edit the `Buy soy milk` task from the example above, the proper command is --``todo edit 3``, or ``todo undo 3`` to un-mark the task as done. -- --Editing tasks can only be done via the TUI interface for now, and cannot be --done via the command line yet. -- --.. _cli: https://en.wikipedia.org/wiki/Command-line_interface --.. _tui: https://en.wikipedia.org/wiki/Text-based_user_interface -- -- --Synchronization ----------------- -- --If you want to synchronize your tasks, you'll need something that syncs via --CalDAV. `vdirsyncer`_ is the recommended tool for this. -- --.. _vdirsyncer: https://vdirsyncer.readthedocs.org/en/stable/ -- --Interactive shell ------------------- -- --If you install `click-repl `_, todoman --gets a new command called ``repl``, which launches an interactive shell with --tab-completion. -- --Integrations -------------- -- --When attempting to integrate ``todoman`` into other systems or parse its --output, you're advised to use the ``--porcelain`` flag, which will print all --output in a pre-defined format that will remain stable regardless of user --configuration or version. -- --The format is JSON, with a single array containing each todo as a single entry --(object). Fields will always be present; if a todo does not have a value for a --given field, it will be printed as ``null``. -- --Fields MAY be added in future, but will never be removed. -- --Conky --````` -- --Todoman can be used with `Conky`_ by using one of the shell execution --`variables`_. --Given the nature of pimutils utilities, there is no need to query new information --every time conky updates so ``execi`` will be the best option most of the time. -- --Adding ``${execi 30 todo}`` inside the text section will display the output of the --command and update it every 30 seconds. -- --A working configuration can be found `here`_. -- --.. _conky: https://conky.cc --.. _variables: https://conky.sourceforge.net/variables.html --.. _here: https://github.com/r4ulill0/todoman/blob/main/docs/examples/conky.conf -- --Sorting --------- -- --The tasks can be sorted with the ``--sort`` argument. Sorting may be done according to the following fields: -- -- - ``description`` -- - ``location`` -- - ``status`` -- - ``summary`` -- - ``uid`` -- - ``rrule`` -- - ``percent_complete`` -- - ``priority`` -- - ``sequence`` -- - ``categories`` -- - ``completed_at`` -- - ``created_at`` -- - ``dtstamp`` -- - ``start`` -- - ``due`` -- - ``last_modified`` -- --It is possible to prepend a ``-`` to a field to sort by that field in ascending --order (by default they are sorted in descending order). -- --Example:: -- -- todo list --sort due,-priority -+.. include:: _usage.rst - -From 117d94135b2b3f374ead08f77a4ccfa52ce9419d Mon Sep 17 00:00:00 2001 -From: Sardorbek Imomaliev -Date: Mon, 21 Jul 2025 09:41:30 +0100 -Subject: [PATCH 03/18] Remove H1 from content files for usage and configure - ---- - docs/source/_configure.rst | 3 --- - docs/source/_usage.rst | 3 --- - 2 files changed, 6 deletions(-) - -diff --git a/docs/source/_configure.rst b/docs/source/_configure.rst -index 7b5b0f16..acdd661b 100644 ---- a/docs/source/_configure.rst -+++ b/docs/source/_configure.rst -@@ -1,6 +1,3 @@ --Configuring --=========== -- - You'll need to configure Todoman before the first usage, using its simple - ini-like configuration file. - -diff --git a/docs/source/_usage.rst b/docs/source/_usage.rst -index ac7ff6d0..593db928 100644 ---- a/docs/source/_usage.rst -+++ b/docs/source/_usage.rst -@@ -1,6 +1,3 @@ --Usage --===== -- - Todoman usage is `CLI`_ based (thought there are some TUI bits, and the - intentions is to also provide a fully `TUI`_-based interface). - - -From 3bc8a27c82b601b06ca78626fe3690e7c440e75c Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Mon, 21 Jul 2025 14:31:36 +0200 -Subject: [PATCH 04/18] docs: improve wording for repl - ---- - docs/source/_usage.rst | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/docs/source/_usage.rst b/docs/source/_usage.rst -index 593db928..29bab103 100644 ---- a/docs/source/_usage.rst -+++ b/docs/source/_usage.rst -@@ -47,8 +47,8 @@ CalDAV. `vdirsyncer`_ is the recommended tool for this. - Interactive shell - ----------------- - --If you install `click-repl `_, todoman --gets a new command called ``repl``, which launches an interactive shell with -+If `click-repl `_ is installed, -+todoman supports the ``repl`` command, which launches an interactive shell with - tab-completion. - - Integrations - -From 8896f43af786ae68ea2d4a8119ba8659ec5d37ec Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:11:14 +0200 -Subject: [PATCH 05/18] Add missing type hints - ---- - todoman/model.py | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/todoman/model.py b/todoman/model.py -index 206e1362..cecd67c9 100644 ---- a/todoman/model.py -+++ b/todoman/model.py -@@ -6,6 +6,7 @@ - import socket - import sqlite3 - import tempfile -+from collections.abc import Generator - from collections.abc import Iterable - from collections.abc import Iterator - from datetime import date -@@ -16,6 +17,7 @@ - from functools import cached_property - from os.path import normpath - from os.path import split -+from typing import IO - from uuid import uuid4 - - import icalendar -@@ -261,9 +263,12 @@ def cancel(self) -> None: - - - @contextlib.contextmanager --def atomic_write(dest, overwrite=False): -+def atomic_write( -+ dest: str, -+ overwrite: bool = False, -+) -> Generator[IO[bytes], None, None]: - fd, src = tempfile.mkstemp(prefix=os.path.basename(dest), dir=os.path.dirname(dest)) -- file = os.fdopen(fd, mode='wb') -+ file = os.fdopen(fd, mode="wb") - - try: - yield file - -From c755df5a44d6517f2ac83e44cf4d536193a8880e Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:13:46 +0200 -Subject: [PATCH 06/18] ruff: use extend-select instead of select - -Ensures that we don't accidentally disable any default rules. ---- - pyproject.toml | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/pyproject.toml b/pyproject.toml -index 78667e9a..d73c2a01 100644 ---- a/pyproject.toml -+++ b/pyproject.toml -@@ -70,9 +70,8 @@ todo = "todoman.cli:cli" - packages = ["todoman"] - - [tool.ruff.lint] --select = [ -+extend-select = [ - "E", -- "F", - "W", - "B", - "I", - -From ecac35e0201208420843cd9e772047d338f8ee8b Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:20:16 +0200 -Subject: [PATCH 07/18] Collapse multiple literals into a single one - ---- - todoman/cli.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/todoman/cli.py b/todoman/cli.py -index ebcf4cef..d4ea7224 100644 ---- a/todoman/cli.py -+++ b/todoman/cli.py -@@ -328,7 +328,7 @@ def formatter(self) -> formatters.Formatter: - @catch_errors - def cli( - click_ctx: click.Context, -- colour: Literal["always"] | Literal["auto"] | Literal["never"], -+ colour: Literal["always", "auto", "never"], - porcelain: bool, - humanize: bool, - config: str, - -From 262155fdb99438bda6948d64a11726e2ea4a7bc1 Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:20:43 +0200 -Subject: [PATCH 08/18] Declare class-mapping as immutable - ---- - todoman/model.py | 39 +++++++++++++++++++++------------------ - 1 file changed, 21 insertions(+), 18 deletions(-) - -diff --git a/todoman/model.py b/todoman/model.py -index cecd67c9..b35e958d 100644 ---- a/todoman/model.py -+++ b/todoman/model.py -@@ -17,6 +17,7 @@ - from functools import cached_property - from os.path import normpath - from os.path import split -+from types import MappingProxyType - from typing import IO - from uuid import uuid4 - -@@ -290,24 +291,26 @@ class VtodoWriter: - """Writes a Todo as a VTODO file.""" - - """Maps Todo field names to VTODO field names""" -- FIELD_MAP = { -- "summary": "summary", -- "priority": "priority", -- "sequence": "sequence", -- "uid": "uid", -- "categories": "categories", -- "completed_at": "completed", -- "description": "description", -- "dtstamp": "dtstamp", -- "start": "dtstart", -- "due": "due", -- "location": "location", -- "percent_complete": "percent-complete", -- "status": "status", -- "created_at": "created", -- "last_modified": "last-modified", -- "rrule": "rrule", -- } -+ FIELD_MAP = MappingProxyType( -+ { -+ "summary": "summary", -+ "priority": "priority", -+ "sequence": "sequence", -+ "uid": "uid", -+ "categories": "categories", -+ "completed_at": "completed", -+ "description": "description", -+ "dtstamp": "dtstamp", -+ "start": "dtstart", -+ "due": "due", -+ "location": "location", -+ "percent_complete": "percent-complete", -+ "status": "status", -+ "created_at": "created", -+ "last_modified": "last-modified", -+ "rrule": "rrule", -+ } -+ ) - - def __init__(self, todo: Todo) -> None: - self.todo = todo - -From f1e8da7c4dd9eed311d5c63d29c558663642303a Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:21:34 +0200 -Subject: [PATCH 09/18] Remove unused variables - ---- - tests/conftest.py | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/tests/conftest.py b/tests/conftest.py -index e3d5f898..c8dc19c4 100644 ---- a/tests/conftest.py -+++ b/tests/conftest.py -@@ -5,8 +5,6 @@ - from collections.abc import Iterable - from datetime import datetime - from typing import Callable --from typing import ParamSpec --from typing import TypeVar - from uuid import uuid4 - - import py -@@ -44,10 +42,6 @@ def config(tmpdir: py.path.local, default_database: model.Database) -> py.path.l - return config_path - - --_T = TypeVar("_T") --_P = ParamSpec("_P") -- -- - @pytest.fixture - def runner(config: py.path.local, sleep: Callable[[], None]) -> CliRunner: - class SleepyCliRunner(CliRunner): - -From 6e6f61eecb1456ab4af9f6e2e50ccf3ee22744d8 Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:22:04 +0200 -Subject: [PATCH 10/18] Use unpacking operator to concatenate collections - ---- - tests/test_config.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/test_config.py b/tests/test_config.py -index 4585723f..a13eef52 100644 ---- a/tests/test_config.py -+++ b/tests/test_config.py -@@ -104,7 +104,7 @@ def test_missing_path( - description=CONFIG_SPEC[0].description, - validation=CONFIG_SPEC[0].validation, - ) -- new_config_spec = [patched_path] + CONFIG_SPEC[1:] -+ new_config_spec = [patched_path, *CONFIG_SPEC[1:]] - - with mock.patch("todoman.configuration.CONFIG_SPEC", new_config_spec): - result = runner.invoke(cli, ["list"]) - -From b4de0b5dbe1f690dafd4aa8e91e8da6e466d32cb Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:23:21 +0200 -Subject: [PATCH 11/18] ruff: enable RUF and PYI rules - ---- - pyproject.toml | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/pyproject.toml b/pyproject.toml -index d73c2a01..6a277ff4 100644 ---- a/pyproject.toml -+++ b/pyproject.toml -@@ -79,10 +79,12 @@ extend-select = [ - "N", - "ANN", - # "A", -- "C4", -+ "C4", # Comprehensions - "PT", - "SIM", - "TID", -+ "RUF", -+ "PYI", - ] - ignore = [ - "ANN002", # Annotations for *args - -From a6fc2f2977e5fe680567b000a396d0dd90d60eb5 Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:24:07 +0200 -Subject: [PATCH 12/18] ruff: sort rules alphabetically - ---- - pyproject.toml | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/pyproject.toml b/pyproject.toml -index 6a277ff4..0cfe2c4d 100644 ---- a/pyproject.toml -+++ b/pyproject.toml -@@ -71,20 +71,20 @@ packages = ["todoman"] - - [tool.ruff.lint] - extend-select = [ -- "E", -- "W", -+ # "A", -+ "ANN", - "B", -+ "C4", # Comprehensions -+ "E", - "I", -- "UP", - "N", -- "ANN", -- # "A", -- "C4", # Comprehensions - "PT", -+ "PYI", -+ "RUF", - "SIM", - "TID", -- "RUF", -- "PYI", -+ "UP", -+ "W", - ] - ignore = [ - "ANN002", # Annotations for *args - -From d07157fc7b459c0553a7ad00354774e8ceae5c21 Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:25:08 +0200 -Subject: [PATCH 13/18] tox: fix missing argument in ruff commands - ---- - tox.ini | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/tox.ini b/tox.ini -index 2d8bbd98..fcd3e77b 100644 ---- a/tox.ini -+++ b/tox.ini -@@ -19,6 +19,6 @@ deps = pyicu - [testenv:lint] - extras = lint - commands = -- ruff check --fix --exit-non-zero-on-fix -- ruff format --diff -+ ruff check --fix --exit-non-zero-on-fix . -+ ruff format --diff . - mypy . - -From 4391b7921776889770788baa0d07b49db9832aba Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Tue, 22 Jul 2025 17:25:42 +0200 -Subject: [PATCH 14/18] ruff: enable INP rules - ---- - pyproject.toml | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/pyproject.toml b/pyproject.toml -index 0cfe2c4d..64775d0a 100644 ---- a/pyproject.toml -+++ b/pyproject.toml -@@ -77,6 +77,7 @@ extend-select = [ - "C4", # Comprehensions - "E", - "I", -+ "INP", - "N", - "PT", - "PYI", - -From bf08791cbdc413068b43f4120020eb512b4f4db2 Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Sat, 26 Jul 2025 19:40:30 +0200 -Subject: [PATCH 15/18] Remove obsolete bin/todo - ---- - CHANGELOG.rst | 6 ++++++ - bin/todo | 7 ------- - docs/source/install.rst | 11 ----------- - 3 files changed, 6 insertions(+), 18 deletions(-) - delete mode 100755 bin/todo - -diff --git a/CHANGELOG.rst b/CHANGELOG.rst -index 81edf594..775a49bb 100644 ---- a/CHANGELOG.rst -+++ b/CHANGELOG.rst -@@ -4,6 +4,12 @@ Changelog - This file contains a brief summary of new features and dependency changes or - releases, in reverse chronological order. - -+v4.7.0 -+------ -+ -+* Removed ``bin/todo``. It is no longer requierd, as the entry point generated -+ by setuptools no longer has performance issues. -+ - v4.6.0 - ------ - -diff --git a/bin/todo b/bin/todo -deleted file mode 100755 -index 44a5e02d..00000000 ---- a/bin/todo -+++ /dev/null -@@ -1,7 +0,0 @@ --#!/usr/bin/env python --from __future__ import annotations -- --from todoman.cli import cli -- --if __name__ == "__main__": -- cli() -diff --git a/docs/source/install.rst b/docs/source/install.rst -index bace8fae..77065d5a 100644 ---- a/docs/source/install.rst -+++ b/docs/source/install.rst -@@ -93,17 +93,6 @@ the setup.py_ file. New dependencies will be clearly announced in the - the third digit of the version is incremented) **will not** introduce new - dependencies. - --If your packages are generated by running ``setup.py install`` or some similar --mechanism, you'll end up with a very slow entry point (that's the --``/usr/bin/todo`` file). Package managers should use the file included in this --repository under ``bin/todo`` and replace the above one. -- --The root cause of the issue is really how python's setuptools generates these --and outside of the scope of this project. -- --If your packages are generated using python wheels, this should not be an issue --(much like it won't be an issue for users installing via ``pip``). -- - .. _setup.py: https://github.com/pimutils/todoman/blob/main/setup.py - - Additionally, `jq` is dependency for zsh's autocompletion. For platforms where - -From 9898b43218556e1e5d41fa437b4e2cd465da8c22 Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Sat, 26 Jul 2025 19:42:22 +0200 -Subject: [PATCH 16/18] Remove outdated references to setup.py - -Fixes: https://github.com/pimutils/todoman/issues/592 ---- - docs/source/contributing.rst | 7 ++++--- - docs/source/install.rst | 24 ++++++++++++++++++------ - 2 files changed, 22 insertions(+), 9 deletions(-) - -diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst -index b1550af1..a2db60d5 100644 ---- a/docs/source/contributing.rst -+++ b/docs/source/contributing.rst -@@ -16,9 +16,10 @@ working on it. - Hacking - ~~~~~~~ - --Runtime dependencies are listed in ``setup.py``. We recommend that you use --virtualenv to make sure that no additional dependencies are required without --them being properly documented. -+Runtime dependencies are listed in ``pyproject.toml``. We recommend that you -+use virtualenv to make sure that no additional dependencies are required -+without them being properly documented. -+ - Run ``pip install -e .`` to install todoman and its dependencies into a - virtualenv. - -diff --git a/docs/source/install.rst b/docs/source/install.rst -index 77065d5a..e5eec170 100644 ---- a/docs/source/install.rst -+++ b/docs/source/install.rst -@@ -43,11 +43,10 @@ Manual installation - ------------------- - - If pip is not available either (this is most unlikely), you'll need to download --the source tarball and install via setup.py, though this is not a recommended -+the source tarball and install via pip, though this is not a recommended - installation method:: - -- python3 setup.py install -- -+ pip install -e . - - bash autocompletion (optional) - ------------------------------ -@@ -87,14 +86,27 @@ Recent versions also have experimental support for pypy3. - Notes for Packagers - ------------------- - --All of todoman's dependencies are listed in the ``install_requires`` section of --the setup.py_ file. New dependencies will be clearly announced in the -+All of todoman's dependencies are listed in the ``dependencies`` section of -+the pyproject.toml_ file. New dependencies will be clearly announced in the - ``CHANGELOG.rst`` file for each release. Patch releases (eg: those where only - the third digit of the version is incremented) **will not** introduce new - dependencies. - --.. _setup.py: https://github.com/pimutils/todoman/blob/main/setup.py -+.. _pyproject.toml: https://github.com/pimutils/todoman/blob/main/pyproject.toml - - Additionally, `jq` is dependency for zsh's autocompletion. For platforms where - `zsh` is the default shell, it is recommended to list `jq` as a dependency, for - others adding it as an optional dependency should suffice. -+ -+A wheel can be build with:: -+ -+ python -m build -+ -+It can then be installed with:: -+ -+ python3 -m installer .dist/*.whl -+ -+When packaging, you usually want to install to a custom directory, rather than -+the root filesystem. For this, use ``-d``:: -+ -+ python3 -m installer -d "$pkgdir" .dist/*.whl - -From 4b6edfc42acc5b2f73f4f92f4aa864a4fff3b745 Mon Sep 17 00:00:00 2001 -From: David Edmondson -Date: Fri, 1 Aug 2025 16:51:11 +0100 -Subject: [PATCH 17/18] Add "recurring" and "list_colour" to the JSON output - (#593) - -* Porcelain (JSON) output should include whether an event recurs - -* Porcelain (JSON) output should include list colours, if any ---- - tests/test_porcelain.py | 12 ++++++++++++ - todoman/formatters.py | 2 ++ - 2 files changed, 14 insertions(+) - -diff --git a/tests/test_porcelain.py b/tests/test_porcelain.py -index d311eff7..14b97bcf 100644 ---- a/tests/test_porcelain.py -+++ b/tests/test_porcelain.py -@@ -35,9 +35,11 @@ def test_list_all(tmpdir: py.path.local, runner: CliRunner, create: Callable) -> - "due": 1451689200, - "id": 1, - "list": "default", -+ "list_colour": None, - "location": "Wherever", - "percent": 26, - "priority": 0, -+ "recurring": False, - "start": 1451606400, - "summary": "Do stuff", - } -@@ -71,9 +73,11 @@ def test_list_start_date( - "due": None, - "id": 1, - "list": "default", -+ "list_colour": None, - "location": "Wherever", - "percent": 26, - "priority": 0, -+ "recurring": False, - "start": 1451692800, - "summary": "Do stuff", - } -@@ -105,9 +109,11 @@ def test_list_due_date( - "due": 1451692800, - "id": 1, - "list": "default", -+ "list_colour": None, - "location": "Wherever", - "percent": 26, - "priority": 0, -+ "recurring": False, - "start": None, - "summary": "Do stuff", - } -@@ -133,8 +139,10 @@ def test_list_nodue(tmpdir: py.path.local, runner: CliRunner, create: Callable) - "due": None, - "id": 1, - "list": "default", -+ "list_colour": None, - "location": "", - "percent": 12, -+ "recurring": False, - "priority": 4, - "start": None, - "summary": "Do stuff", -@@ -203,9 +211,11 @@ def test_show(tmpdir: py.path.local, runner: CliRunner, create: Callable) -> Non - "due": None, - "id": 1, - "list": "default", -+ "list_colour": None, - "location": "", - "percent": 0, - "priority": 5, -+ "recurring": False, - "start": None, - "summary": "harhar", - } -@@ -226,9 +236,11 @@ def test_simple_action(todo_factory: Callable) -> None: - "due": None, - "id": 7, - "list": "default", -+ "list_colour": None, - "location": "Downtown", - "percent": 0, - "priority": 0, -+ "recurring": False, - "start": None, - "summary": "YARR!", - } -diff --git a/todoman/formatters.py b/todoman/formatters.py -index eb1e5bf2..2424eef3 100644 ---- a/todoman/formatters.py -+++ b/todoman/formatters.py -@@ -304,6 +304,7 @@ def _todo_as_dict(self, todo: Todo) -> dict: - "due": self.format_datetime(todo.due), - "id": todo.id, - "list": todo.list.name if todo.list else None, -+ "list_colour": todo.list.colour if todo.list else None, - "percent": todo.percent_complete, - "summary": todo.summary, - "categories": todo.categories, -@@ -311,6 +312,7 @@ def _todo_as_dict(self, todo: Todo) -> dict: - "location": todo.location, - "description": todo.description, - "completed_at": self.format_datetime(todo.completed_at), -+ "recurring": todo.is_recurring, - } - - def compact(self, todo: Todo) -> str: - -From bd417730a6ee761734d07686511c24a1ba7cebda Mon Sep 17 00:00:00 2001 -From: Hugo Osvaldo Barrera -Date: Thu, 28 Aug 2025 11:31:11 +0200 -Subject: [PATCH 18/18] Update stale references to setup.py - ---- - docs/source/contributing.rst | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst -index a2db60d5..98d0349c 100644 ---- a/docs/source/contributing.rst -+++ b/docs/source/contributing.rst -@@ -111,12 +111,12 @@ We appreciate distributions packaging todoman. Packaging should be relatively - straightforward following usual Python package guidelines. We recommend that - you git-clone tags, and build from source, since these tags are GPG signed. - --Dependencies are listed in ``setup.py``. Please also try to include the --extras dependencies as optional dependencies (or what maps best for your --distribution). -+Dependencies are listed in ``pyproject.toml``. Please also try to include the -+extras dependencies as optional dependencies (or whatever equivalent is best -+for your distribution). - --You'll need to run ``python setup.py build`` to generate the --``todoman/version.py`` file which is necessary at runtime. -+You'll need to run ``python -m build`` to generate the ``todoman/version.py`` -+file which is necessary at runtime. - - We recommend that you include the :doc:`man` in distribution packages. You can - build this by running:: diff --git a/overlays/todoman-subtasks.patch b/overlays/todoman-subtasks.patch index ced063de..2ab1c1c1 100644 --- a/overlays/todoman-subtasks.patch +++ b/overlays/todoman-subtasks.patch @@ -1,24 +1,22 @@ -From 87fc93e8017083485e12c9a7906eba21b26d1e91 Mon Sep 17 00:00:00 2001 +From 7817f29220c615a7ad3ee62a1c168b842a8d3128 Mon Sep 17 00:00:00 2001 From: powerjungle Date: Mon, 25 Aug 2025 20:21:24 +0200 -Subject: [PATCH 1/8] feat!: add support for `RELATED-TO` property and - `RELTYPE` parameter +Subject: [PATCH 1/9] feat: add support for `RELATED-TO` property and `RELTYPE` + parameter Taken from RFC 5545, section `3.8.4.5`. If present in a file, these values are now read and stored in the cache. Nothing in the UI has been changed. Tests are modified to reflect the change. -BREAKING CHANGE: The cache has to be deleted manually and recreated if -the cache was previously created using a version of the code, -that is older than this commit. +Increment `SCHEMA_VERSION` to allow cache recreation on todoman update. --- tests/test_backend.py | 6 ++++++ tests/test_model.py | 10 ++++++++++ - todoman/model.py | 34 +++++++++++++++++++++++++++++++--- - 3 files changed, 47 insertions(+), 3 deletions(-) + todoman/model.py | 41 +++++++++++++++++++++++++++++++++++++---- + 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/tests/test_backend.py b/tests/test_backend.py -index 2a09a6b5..decd110f 100644 +index bf3f0f1..821bb77 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -49,6 +49,8 @@ def test_supported_fields_are_serializeable() -> None: @@ -35,7 +33,7 @@ index 2a09a6b5..decd110f 100644 summary="Some tea", rrule="FREQ=MONTHLY", + related_to=related_val, -+ related_to_reltype=related_val_reltype ++ related_to_reltype=related_val_reltype, ) writer = VtodoWriter(todo) vtodo = writer.serialize() @@ -44,15 +42,15 @@ index 2a09a6b5..decd110f 100644 assert str(vtodo.get("status")) == "IN-PROCESS" assert vtodo.get("rrule") == icalendar.vRecur.from_ical("FREQ=MONTHLY") + assert vtodo.get("related-to") == related_val -+ assert vtodo.get("related-to").params.get('reltype') == related_val_reltype ++ assert vtodo.get("related-to").params.get("reltype") == related_val_reltype @freeze_time("2017-04-04 20:11:57") diff --git a/tests/test_model.py b/tests/test_model.py -index cdb5d0bc..d029016f 100644 +index a1989f9..d122039 100644 --- a/tests/test_model.py +++ b/tests/test_model.py -@@ -250,6 +250,12 @@ def test_todo_setters(todo_factory: Callable) -> None: +@@ -260,6 +260,12 @@ def test_todo_setters(todo_factory: Callable) -> None: todo.due = None assert todo.due is None @@ -65,7 +63,7 @@ index cdb5d0bc..d029016f 100644 @freeze_time("2017-03-19-15") def test_is_completed() -> None: -@@ -391,6 +397,8 @@ def test_clone() -> None: +@@ -401,6 +407,8 @@ def test_clone() -> None: todo.uid = "123" todo.id = 123 todo.filename = "123.ics" @@ -74,7 +72,7 @@ index cdb5d0bc..d029016f 100644 clone = todo.clone() -@@ -402,6 +410,8 @@ def test_clone() -> None: +@@ -412,6 +420,8 @@ def test_clone() -> None: assert clone.id is None assert todo.filename != clone.filename assert clone.uid in clone.filename @@ -84,7 +82,7 @@ index cdb5d0bc..d029016f 100644 @freeze_time("2017, 3, 20") diff --git a/todoman/model.py b/todoman/model.py -index b35e958d..444d0811 100644 +index 0411eee..bce806d 100644 --- a/todoman/model.py +++ b/todoman/model.py @@ -55,6 +55,8 @@ class Todo: @@ -96,7 +94,7 @@ index b35e958d..444d0811 100644 start: date | None id: int | None -@@ -93,6 +95,8 @@ def __init__( +@@ -93,6 +95,8 @@ class Todo: self.location = "" self.percent_complete = 0 self.priority = 0 @@ -105,7 +103,7 @@ index b35e958d..444d0811 100644 self.rrule = "" self.sequence = 0 self.start = None -@@ -126,6 +130,8 @@ def clone(self) -> Todo: +@@ -126,6 +130,8 @@ class Todo: for field in fields: setattr(todo, field, getattr(self, field)) @@ -114,7 +112,7 @@ index b35e958d..444d0811 100644 return todo STRING_FIELDS = ( -@@ -135,6 +141,7 @@ def clone(self) -> Todo: +@@ -135,6 +141,7 @@ class Todo: "summary", "uid", "rrule", @@ -122,7 +120,7 @@ index b35e958d..444d0811 100644 ) INT_FIELDS = ( "percent_complete", -@@ -309,6 +316,7 @@ class VtodoWriter: +@@ -314,6 +321,7 @@ class VtodoWriter: "created_at": "created", "last_modified": "last-modified", "rrule": "rrule", @@ -130,7 +128,7 @@ index b35e958d..444d0811 100644 } ) -@@ -355,7 +363,14 @@ def serialize(self, original: icalendar.Todo = None) -> icalendar.Todo: +@@ -360,7 +368,14 @@ class VtodoWriter: elif source in Todo.INT_FIELDS: value = int(raw) elif source in Todo.STRING_FIELDS: @@ -139,14 +137,32 @@ index b35e958d..444d0811 100644 + set_params = {} + reltype_value = self.todo.related_to_reltype + if reltype_value != "": -+ set_params = {'reltype': reltype_value} ++ set_params = {"reltype": reltype_value} + value = icalendar.prop.vText(raw, params=set_params) + else: + value = raw else: raise Exception(f"Unknown field {source} serialized.") -@@ -533,6 +548,8 @@ def create_tables(self) -> None: +@@ -427,11 +442,16 @@ class Cache: + load times, but, more importantly, provides a simpler interface for + filtering/querying/sorting. + ++ The `SCHEMA_VERSION` should be incremented when breaking changes to the ++ database are made. For example adding new fields or removing no longer ++ needed fields and etc. This will ensure that the cache is rebuilt ++ automatically after todoman was updated. ++ + [1]: Relevant fields are those we show when listing todos, or those which + may be used for filtering/sorting. + """ + +- SCHEMA_VERSION = 10 ++ SCHEMA_VERSION = 11 + + def __init__(self, path: str) -> None: + self.cache_path = str(path) +@@ -545,6 +565,8 @@ class Cache: "sequence" INTEGER, "last_modified" INTEGER, "rrule" TEXT, @@ -155,7 +171,7 @@ index b35e958d..444d0811 100644 FOREIGN KEY(file_path) REFERENCES files(path) ON DELETE CASCADE ); -@@ -657,6 +674,11 @@ def add_vtodo( +@@ -669,6 +691,11 @@ class Cache: :param todo: The icalendar component object on which """ @@ -167,7 +183,7 @@ index b35e958d..444d0811 100644 sql = """ INSERT INTO todos ( {} -@@ -677,9 +699,11 @@ def add_vtodo( +@@ -689,9 +716,11 @@ class Cache: location, sequence, last_modified, @@ -181,7 +197,7 @@ index b35e958d..444d0811 100644 """ due, due_dt = self._serialize_datetime(todo, "due") -@@ -707,6 +731,8 @@ def add_vtodo( +@@ -719,6 +748,8 @@ class Cache: todo.get("sequence", 1), self._serialize_datetime(todo, "last-modified")[0], self._serialize_rrule(todo, "rrule"), @@ -190,7 +206,7 @@ index b35e958d..444d0811 100644 ] if id: -@@ -917,6 +943,8 @@ def _todo_from_db(self, row: dict) -> Todo: +@@ -929,6 +960,8 @@ class Cache: todo.list = self.lists_map[row["list_name"]] todo.filename = os.path.basename(row["path"]) todo.rrule = row["rrule"] @@ -199,18 +215,21 @@ index b35e958d..444d0811 100644 return todo def lists(self) -> Iterator[TodoList]: +-- +2.53.0 -From b8fbc9fc95eb23bb50c07a13ac3c3e0d43a0df08 Mon Sep 17 00:00:00 2001 + +From e40e99897f8589ea5699b09378d66494a8981f23 Mon Sep 17 00:00:00 2001 From: powerjungle Date: Mon, 25 Aug 2025 20:38:01 +0200 -Subject: [PATCH 2/8] chore(gitignore): add `.mypy_cache/` +Subject: [PATCH 2/9] chore(gitignore): add `.mypy_cache/` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore -index 4d443c0a..911a0e5a 100644 +index 4d443c0..911a0e5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,6 @@ docs/_build/ @@ -220,11 +239,14 @@ index 4d443c0a..911a0e5a 100644 +.mypy_cache/ todoman/version.py +-- +2.53.0 -From 0fa9d37d3bdb2d0f5e673b5ccd608f40603256ec Mon Sep 17 00:00:00 2001 + +From b57a13ea62a236e93a9ce44487587155f09c30be Mon Sep 17 00:00:00 2001 From: powerjungle Date: Wed, 3 Sep 2025 18:48:56 +0200 -Subject: [PATCH 3/8] feat(porcelain): add `related_to` and +Subject: [PATCH 3/9] feat(porcelain): add `related_to` and `related_to_reltype` New names and values added to the JSON output for the `RELATED-TO` @@ -235,7 +257,7 @@ property. 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/test_porcelain.py b/tests/test_porcelain.py -index 14b97bcf..5d53c997 100644 +index e54d8f9..ce7c04f 100644 --- a/tests/test_porcelain.py +++ b/tests/test_porcelain.py @@ -22,7 +22,8 @@ def test_list_all(tmpdir: py.path.local, runner: CliRunner, create: Callable) -> @@ -303,10 +325,10 @@ index 14b97bcf..5d53c997 100644 "summary": "YARR!", } diff --git a/todoman/formatters.py b/todoman/formatters.py -index 2424eef3..88f7cee6 100644 +index 2424eef..88f7cee 100644 --- a/todoman/formatters.py +++ b/todoman/formatters.py -@@ -313,6 +313,8 @@ def _todo_as_dict(self, todo: Todo) -> dict: +@@ -313,6 +313,8 @@ class PorcelainFormatter(DefaultFormatter): "description": todo.description, "completed_at": self.format_datetime(todo.completed_at), "recurring": todo.is_recurring, @@ -315,11 +337,14 @@ index 2424eef3..88f7cee6 100644 } def compact(self, todo: Todo) -> str: +-- +2.53.0 -From 2c0cea31bfc9e2d0745d1c0c219c5e31089b000b Mon Sep 17 00:00:00 2001 + +From 9b557d41c629e415e9182664c92e071d742990e2 Mon Sep 17 00:00:00 2001 From: powerjungle Date: Sun, 7 Sep 2025 21:06:58 +0200 -Subject: [PATCH 4/8] feat(formatters): indentated output for related tasks +Subject: [PATCH 4/9] feat(formatters): indentated output for related tasks (subtasks) List text output is now with a tree structure: @@ -339,51 +364,44 @@ Includes output space formatting fixes. Tests adjusted to changes. --- - tests/test_cli.py | 13 ++-- + tests/test_cli.py | 16 ++--- tests/test_formatter.py | 10 +-- - todoman/formatters.py | 148 +++++++++++++++++++++++++++++++++------- - 3 files changed, 136 insertions(+), 35 deletions(-) + todoman/formatters.py | 142 ++++++++++++++++++++++++++++++++++------ + 3 files changed, 134 insertions(+), 34 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py -index 75e0cabd..315faf0f 100644 +index b85bec8..7de9b3b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py -@@ -472,7 +472,8 @@ def test_color_due_dates( - due = datetime.datetime.now() + datetime.timedelta(hours=hours) - create( - "test.ics", -- "SUMMARY:aaa\nSTATUS:IN-PROCESS\nDUE;VALUE=DATE-TIME;TZID=ART:{}\n".format( -+ "SUMMARY:aaa\nSTATUS:IN-PROCESS\nDUE;VALUE=DATE-TIME;TZID=ART:{}\n" -+ .format( - due.strftime("%Y%m%dT%H%M%S") - ), - ) -@@ -482,11 +483,11 @@ def test_color_due_dates( +@@ -484,13 +484,9 @@ def test_color_due_dates( + assert not result.exception due_str = due.strftime("%Y-%m-%d") if hours == 72: - expected = ( +- expected = ( - f"[ ] 1 \x1b[35m\x1b[0m \x1b[37m{due_str}\x1b[0m aaa @default\x1b[0m\n" -+ f"[ ] 1 \x1b[37m{due_str}\x1b[0m aaa @default\x1b[0m\n" - ) +- ) ++ expected = f"[ ] 1 \x1b[37m{due_str}\x1b[0m aaa @default\x1b[0m\n" else: - expected = ( +- expected = ( - f"[ ] 1 \x1b[35m\x1b[0m \x1b[31m{due_str}\x1b[0m aaa @default\x1b[0m\n" -+ f"[ ] 1 \x1b[31m{due_str}\x1b[0m aaa @default\x1b[0m\n" - ) +- ) ++ expected = f"[ ] 1 \x1b[31m{due_str}\x1b[0m aaa @default\x1b[0m\n" assert result.output == expected -@@ -497,16 +498,16 @@ def test_color_flag(runner: CliRunner, todo_factory: Callable) -> None: + +@@ -499,17 +495,15 @@ def test_color_flag(runner: CliRunner, todo_factory: Callable) -> None: + result = runner.invoke(cli, ["--color", "always"], color=True) assert ( - result.output.strip() +- result.output.strip() - == "[ ] 1 \x1b[35m\x1b[0m \x1b[31m2007-03-22\x1b[0m YARR! @default\x1b[0m" -+ == "[ ] 1 \x1b[31m2007-03-22\x1b[0m YARR! @default\x1b[0m" ++ result.output.strip() == "[ ] 1 \x1b[31m2007-03-22\x1b[0m YARR! @default\x1b[0m" ) result = runner.invoke(cli, color=True) assert ( - result.output.strip() +- result.output.strip() - == "[ ] 1 \x1b[35m\x1b[0m \x1b[31m2007-03-22\x1b[0m YARR! @default\x1b[0m" -+ == "[ ] 1 \x1b[31m2007-03-22\x1b[0m YARR! @default\x1b[0m" ++ result.output.strip() == "[ ] 1 \x1b[31m2007-03-22\x1b[0m YARR! @default\x1b[0m" ) result = runner.invoke(cli, ["--color", "never"], color=True) @@ -393,17 +411,17 @@ index 75e0cabd..315faf0f 100644 def test_flush( diff --git a/tests/test_formatter.py b/tests/test_formatter.py -index 8676d4a6..fefdf53f 100644 +index 15946fb..d5075c2 100644 --- a/tests/test_formatter.py +++ b/tests/test_formatter.py -@@ -108,15 +108,17 @@ def test_format_datetime(default_formatter: DefaultFormatter) -> None: +@@ -106,15 +106,17 @@ def test_format_datetime(default_formatter: DefaultFormatter) -> None: def test_detailed_format(runner: CliRunner, todo_factory: Callable) -> None: todo_factory( description=( - "Test detailed formatting\nThis includes multiline descriptions\nBlah!" -+ "Test detailed formatting\n" + -+ "This includes multiline descriptions\n" + -+ "Blah!" ++ "Test detailed formatting\n" ++ + "This includes multiline descriptions\n" ++ + "Blah!" ), location="Over the hills, and far away", ) @@ -417,7 +435,7 @@ index 8676d4a6..fefdf53f 100644 "", "Description:", "Test detailed formatting", -@@ -204,7 +206,7 @@ def test_format_multiple_with_list( +@@ -202,7 +204,7 @@ def test_format_multiple_with_list( assert todo.list assert ( default_formatter.compact_multiple([todo]) @@ -427,28 +445,17 @@ index 8676d4a6..fefdf53f 100644 diff --git a/todoman/formatters.py b/todoman/formatters.py -index 88f7cee6..848c9d95 100644 +index 88f7cee..f3a4bd0 100644 --- a/todoman/formatters.py +++ b/todoman/formatters.py -@@ -20,7 +20,6 @@ - from todoman.model import Todo - from todoman.model import TodoList - -- - def rgb_to_ansi(colour: str | None) -> str | None: - """ - Convert a string containing an RGB colour to ANSI escapes -@@ -119,52 +118,151 @@ def simple_action(self, action: str, todo: Todo) -> str: - def compact(self, todo: Todo) -> str: +@@ -120,51 +120,155 @@ class DefaultFormatter(Formatter): return self.compact_multiple([todo]) -- def compact_multiple(self, todos: Iterable[Todo], hide_list: bool = False) -> str: + def compact_multiple(self, todos: Iterable[Todo], hide_list: bool = False) -> str: - # TODO: format lines fuidly and drop the table - # it can end up being more readable when too many columns are empty. - # show dates that are in the future in yellow (in 24hs) or grey (future) - table = [] -+ def compact_multiple(self, todos: Iterable[Todo], -+ hide_list: bool = False) -> str: + # TODO: show dates that are in the future in yellow (in 24hs) + # or grey (future) + @@ -480,8 +487,7 @@ index 88f7cee6..848c9d95 100644 + # Source: + # https://www.rfc-editor.org/rfc/rfc9253#section-9.1 + if todo.related_to != "": -+ if todo.related_to_reltype == "PARENT" \ -+ or todo.related_to_reltype == "": ++ if todo.related_to_reltype == "PARENT" or todo.related_to_reltype == "": + related_todos[todo.uid] = [todo.related_to, None] + elif todo.related_to_reltype == "CHILD": + related_todos[todo.related_to] = [todo.uid, None] @@ -506,7 +512,10 @@ index 88f7cee6..848c9d95 100644 - ) + priority = self.format_priority_compact(todo.priority) + if priority != "": -+ priority = click.style(priority + " ", fg="magenta",) ++ priority = click.style( ++ priority + " ", ++ fg="magenta", ++ ) due = self.format_datetime(todo.due) or "(no due date)" due_colour = self._due_colour(todo) @@ -523,31 +532,29 @@ index 88f7cee6..848c9d95 100644 if not todo.list: raise ValueError("Cannot format todo without a list") -- summary = f"{todo.summary} {self.format_database(todo.list)}{percent}" -- + summary = f"{todo.summary} {self.format_database(todo.list)}{percent}" + - # TODO: add spaces on the left based on max todos" -- ++ tree[todo.uid] = [ ++ f"[{completed}] {todo.id} {priority}{due} " ++ f"{recurring}{summary} {categories}\n", ++ None, ++ ] + - # FIXME: double space when no priority - # split into parts to satisfy linter line too long - table.append( - f"[{completed}] {todo.id} {priority} {due} " - f"{recurring}{summary}{categories}" - ) -- -- return "\n".join(table) -+ summary = f"{todo.summary} "\ -+ f"{self.format_database(todo.list)}{percent}" -+ -+ tree[todo.uid] = [f"[{completed}] {todo.id} {priority}{due} " -+ f"{recurring}{summary} {categories}\n", -+ None] -+ + self._tree_reorder_related(tree, related_todos) -+ + +- return "\n".join(table) + return self._join_tree(tree).strip() + -+ def _tree_reorder_related(self, tree: dict[str, list], -+ related_todos: dict[str, list]) -> None: ++ def _tree_reorder_related( ++ self, tree: dict[str, list], related_todos: dict[str, list] ++ ) -> None: + """Move all related todos to their proper positions within the tree + dictionary.""" + store_path: list = [] @@ -556,8 +563,7 @@ index 88f7cee6..848c9d95 100644 + related_to_path_tracer: str = related_to[0] + related_dict: dict[str, list] = tree + while related_to_path_tracer in related_todos: -+ related_to_path_tracer = \ -+ related_todos[related_to_path_tracer][0] ++ related_to_path_tracer = related_todos[related_to_path_tracer][0] + store_path.append(related_to_path_tracer) + + # Walk from the parent root todo, down to the @@ -578,14 +584,17 @@ index 88f7cee6..848c9d95 100644 + related_dict = tree + break + -+ self._tree_move_related(related, related_to[0], -+ tree, related_dict) ++ self._tree_move_related(related, related_to[0], tree, related_dict) + + store_path.clear() + -+ def _tree_move_related(self, related: str, to: str, -+ tree: dict[str, list], -+ related_dict: dict[str, list] | None) -> None: ++ def _tree_move_related( ++ self, ++ related: str, ++ to: str, ++ tree: dict[str, list], ++ related_dict: dict[str, list] | None, ++ ) -> None: + """Move a todo from the top of the tree dictionary, to the child + dictionary of a todo.""" + if related_dict is None: @@ -614,37 +623,26 @@ index 88f7cee6..848c9d95 100644 def _due_colour(self, todo: Todo) -> str: now = self.now if isinstance(todo.due, datetime) else self.now.date() +-- +2.53.0 -From 967e532a7ca4573794adc1735100e3c4f726a15a Mon Sep 17 00:00:00 2001 + +From 5707b8ae25fa47c3322cb500c776c1d35087cf2b Mon Sep 17 00:00:00 2001 From: powerjungle Date: Mon, 8 Sep 2025 16:53:32 +0200 -Subject: [PATCH 5/8] refactor(cli): description of `_todo_property_options` +Subject: [PATCH 5/9] refactor(cli): description of `_todo_property_options` wrapper Comment for describing the weird code for merging arguments. --- - todoman/cli.py | 18 ++++++++++++++---- - 1 file changed, 14 insertions(+), 4 deletions(-) + todoman/cli.py | 7 +++++++ + 1 file changed, 7 insertions(+) diff --git a/todoman/cli.py b/todoman/cli.py -index d4ea7224..44f8818b 100644 +index 5d7a44f..9488405 100644 --- a/todoman/cli.py +++ b/todoman/cli.py -@@ -220,9 +220,10 @@ def _todo_property_options(command: Callable) -> Callable: - callback=_validate_priority_param, - help="Priority for this task", - )(command) -- click.option("--location", help="The location where this todo takes place.")( -- command -- ) -+ click.option( -+ "--location", -+ help="The location where this todo takes place." -+ )(command) - click.option( - "--due", - "-d", -@@ -238,10 +239,19 @@ def _todo_property_options(command: Callable) -> Callable: +@@ -238,6 +238,13 @@ def _todo_property_options(command: Callable) -> Callable: help="When the task starts.", )(command) @@ -658,18 +656,14 @@ index d4ea7224..44f8818b 100644 @functools.wraps(command) def command_wrap(*a, **kw) -> click.Command: kw["todo_properties"] = { -- key: kw.pop(key) for key in ("due", "start", "location", "priority") -+ key: kw.pop(key) for key in ( -+ "due", "start", "location", "priority" -+ ) - } - # longform is singular since user can pass it multiple times, but - # in actuality it's plural, so manually changing for #cache.todos. +-- +2.53.0 -From c44baba6bc5d3fbdf3397f245c2a8d87382052d5 Mon Sep 17 00:00:00 2001 + +From 64f4b6bacddeb4b144bf8018034a0c0e3a119753 Mon Sep 17 00:00:00 2001 From: powerjungle Date: Mon, 8 Sep 2025 18:11:52 +0200 -Subject: [PATCH 6/8] feat(cli): support for editing and adding subtasks +Subject: [PATCH 6/9] feat(cli): support for editing and adding subtasks Using the newly supported attributes, two new options are added. `--subtask-for`, making a task be a subtask for another and @@ -680,10 +674,10 @@ The commands `new` and `edit` are fitted with these new options. 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/todoman/cli.py b/todoman/cli.py -index 44f8818b..26b0319b 100644 +index 9488405..0fd59df 100644 --- a/todoman/cli.py +++ b/todoman/cli.py -@@ -53,7 +53,9 @@ def wrapper(*a, **kw) -> _T: +@@ -54,7 +54,9 @@ def catch_errors(f: Callable[_P, _T]) -> Callable[_P, _T]: TODO_ID_MIN = 1 @@ -694,7 +688,7 @@ index 44f8818b..26b0319b 100644 def _validate_lists_param( -@@ -294,6 +296,21 @@ def formatter(self) -> formatters.Formatter: +@@ -291,6 +293,21 @@ _interactive_option = click.option( help="Go into interactive mode before saving the task.", ) @@ -716,7 +710,7 @@ index 44f8818b..26b0319b 100644 @click.group(invoke_without_command=True) @click_log.simple_verbosity_option() -@@ -432,6 +449,7 @@ def repl(ctx: click.Context) -> None: +@@ -430,6 +447,7 @@ def repl(ctx: click.Context) -> None: ) @_todo_property_options @_interactive_option @@ -724,15 +718,15 @@ index 44f8818b..26b0319b 100644 @pass_ctx @catch_errors def new( -@@ -441,6 +459,7 @@ def new( +@@ -439,6 +457,7 @@ def new( todo_properties: dict, read_description: bool, interactive: bool, -+ subtask_for: int | None ++ subtask_for: int | None, ) -> None: """ Create a new task with SUMMARY. -@@ -462,6 +481,11 @@ def new( +@@ -460,6 +479,11 @@ def new( setattr(todo, key, value) todo.summary = " ".join(summary) @@ -744,7 +738,7 @@ index 44f8818b..26b0319b 100644 if read_description: todo.description = sys.stdin.read() -@@ -496,6 +520,8 @@ def new( +@@ -494,6 +518,8 @@ def new( ) @_todo_property_options @_interactive_option @@ -753,16 +747,16 @@ index 44f8818b..26b0319b 100644 @with_id_arg @catch_errors def edit( -@@ -505,6 +531,8 @@ def edit( +@@ -503,6 +529,8 @@ def edit( interactive: bool, read_description: bool, raw: bool, + subtask_for: int | None, -+ not_subtask: bool ++ not_subtask: bool, ) -> None: """ Edit the task with id ID. -@@ -525,6 +553,17 @@ def edit( +@@ -523,6 +551,17 @@ def edit( changes = True todo.description = sys.stdin.read() @@ -780,7 +774,7 @@ index 44f8818b..26b0319b 100644 if interactive or (not changes and interactive is None): ui = TodoEditor(todo, ctx.db.lists(), ctx.ui_formatter) ui.edit() -@@ -537,6 +576,7 @@ def edit( +@@ -535,6 +574,7 @@ def edit( ctx.db.save(todo) if old_list != new_list: ctx.db.move(todo, new_list=new_list, from_list=old_list) @@ -788,58 +782,53 @@ index 44f8818b..26b0319b 100644 click.echo(ctx.formatter.detailed(todo)) +-- +2.53.0 -From 5047eb71e3b33d4d248ca9d48bbd8ecd2c7c638d Mon Sep 17 00:00:00 2001 + +From 977ea6e8934ada8d9407b037c9ffd3ba51dfe56c Mon Sep 17 00:00:00 2001 From: powerjungle Date: Mon, 8 Sep 2025 18:44:37 +0200 -Subject: [PATCH 7/8] chore(CHANGELOG): describe new breaking change from - subtasks +Subject: [PATCH 7/9] chore(CHANGELOG): describe new subtasks feature --- - CHANGELOG.rst | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) + CHANGELOG.rst | 8 ++++++++ + 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst -index 775a49bb..601f23ff 100644 +index a990ba2..4f816f5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst -@@ -4,9 +4,23 @@ Changelog +@@ -4,6 +4,14 @@ Changelog This file contains a brief summary of new features and dependency changes or releases, in reverse chronological order. --v4.7.0 -+v5.0.0 ++v4.8.0 ++------ ++* Added support for RELATED-TO property and RELTYPE parameter, allowing the ++ parsing and creation of subtasks. This requires adding two new columns to ++ the database. The `SCHEMA_VERSION` has been incremented, so the cache will ++ be recreated. No changes to the configuration or lists is needed. The tasks ++ are now printed as a tree when subtasks are present. ++ + v4.7.0 ------ -+Breaking changes to the database -+******************************** -+ -+Added support for RELATED-TO property and RELTYPE parameter, allowing the -+parsing and creation of subtasks. This requires adding two new columns to -+the database. -+ -+The cache has to be deleted manually and recreated if the cache was previously -+created using a version of the code, that is older than this release. -+ -+No changes to the configuration or lists is needed. -+ -+The tasks are now printed as a tree when subtasks are present. -+ - * Removed ``bin/todo``. It is no longer requierd, as the entry point generated - by setuptools no longer has performance issues. +-- +2.53.0 -From e87552a1c21357caea826863e4c1da5f6e0a3797 Mon Sep 17 00:00:00 2001 +From 4cd86ac883e7995f1c57d6024e07df09441a6450 Mon Sep 17 00:00:00 2001 From: powerjungle Date: Mon, 8 Sep 2025 18:48:07 +0200 -Subject: [PATCH 8/8] chore(AUTHORS): add powerjungle +Subject: [PATCH 8/9] chore(AUTHORS): add powerjungle --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst -index 558e93a2..771fde96 100644 +index 558e93a..771fde9 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -34,3 +34,4 @@ Authors are listed in alphabetical order. @@ -847,3 +836,35 @@ index 558e93a2..771fde96 100644 * Thomas Glanzmann * https://github.com/Pikrass +* https://github.com/powerjungle +-- +2.53.0 + + +From 4e7d91df489e26b65b54ee5c08ca8d7f932a052c Mon Sep 17 00:00:00 2001 +From: powerjungle +Date: Wed, 1 Oct 2025 16:49:40 +0200 +Subject: [PATCH 9/9] docs(Hacking): new description of `SCHEMA_VERSION` + variable + +--- + docs/source/contributing.rst | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst +index 98d0349..48433b9 100644 +--- a/docs/source/contributing.rst ++++ b/docs/source/contributing.rst +@@ -23,6 +23,11 @@ without them being properly documented. + Run ``pip install -e .`` to install todoman and its dependencies into a + virtualenv. + ++If the database is changed in a breaking way, the ``SCHEMA_VERSION`` variable ++in the class ``Cache`` has to be incremented to allow the cache to be recreated ++after todoman has been updated. An example would be adding new fields or ++removing old unnecessary fields and etc. ++ + We use ``pre-commit`` to run style and convention checks. Run ``pre-commit + install``` to install our git-hooks. These will check code style and inform you + of any issues when attempting to commit. This will also run ``black`` to +-- +2.53.0