nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: pimutils/todoman
Pull request #174 (2017-03-04 16:44:54)

Fix crash when UI-editing a todo with priority


Patch:
diff --git a/todoman/ui.py b/todoman/ui.py
index f650d04..8503ca2 100644
--- a/todoman/ui.py
+++ b/todoman/ui.py
@@ -41,11 +41,7 @@ class TodoEditor:
 
         due = formatter.format_datetime(todo.due, humanize=False) or ''
         dtstart = formatter.format_datetime(todo.start, humanize=False) or ''
-
-        if todo.priority:
-            priority = formatter.parse_priority(todo.priority, humanize=False)
-        else:
-            priority = ''
+        priority = formatter.format_priority(todo.priority)
 
         self._summary = widgets.ExtendedEdit(parent=self,
                                              edit_text=todo.summary)
@@ -330,6 +326,16 @@ class TodoFormatter:
             raise ValueError('Priority has to be one of low, medium,'
                              ' high or none')
 
+    def format_priority(self, priority):
+        if not priority:
+            return ''
+        elif 1 <= priority <= 4:
+            return 'high'
+        elif priority == 5:
+            return 'medium'
+        elif 6 <= priority <= 9:
+            return 'low'
+
     def parse_datetime(self, dt):
         if not dt:
             return None


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index a51e9ca..58133f2 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -71,10 +71,11 @@ def now_for_tz():
 
 @pytest.fixture
 def todo_factory(default_database):
-    def inner():
+    def inner(priority=None):
         todo = model.FileTodo()
         todo.list = list(default_database.lists())[0]
         todo.summary = 'YARR!'
+        todo.priority = priority
         todo.save()
 
         return todo
diff --git a/tests/test_ui.py b/tests/test_ui.py
index 57f8680..35cb3e3 100644
--- a/tests/test_ui.py
+++ b/tests/test_ui.py
@@ -8,7 +8,7 @@ TIME_FORMAT = "%H:%M"
 
 
 def test_todo_editor_priority(default_database, todo_factory):
-    todo = todo_factory()
+    todo = todo_factory(priority=1)
     lists = list(default_database.lists())
     formatter = TodoFormatter(DATE_FORMAT, TIME_FORMAT, '')
Repository: pimutils/todoman
Pull request #199 (2017-03-21 02:09:43)

Fix a bug serializing created_at/start
These fields weren't being serialized. Check that we serialize them, and also make sure that all supported fields are serializeable and viceversa.


Patch:
diff --git a/todoman/model.py b/todoman/model.py
index b7abb6c..313efbd 100644
--- a/todoman/model.py
+++ b/todoman/model.py
@@ -258,12 +258,9 @@ class VtodoWritter:
         if name in Todo.STRING_FIELDS:
             return value
 
-        logger.warn('Unknown field %s serialized.', name)
-        return value
+        raise Exception('Unknown field {} serialized.'.format(name))
 
     def set_field(self, name, value):
-        value = self.serialize_field(name, value)
-
         if name in self.vtodo:
             del(self.vtodo[name])
         if value:
@@ -278,7 +275,10 @@ class VtodoWritter:
 
         for source, target in self.FIELD_MAP.items():
             if getattr(self.todo, source):
-                self.set_field(target, getattr(self.todo, source))
+                self.set_field(
+                    target,
+                    self.serialize_field(source, getattr(self.todo, source)),
+                )
 
         return self.vtodo
 


Test patch:
diff --git a/tests/test_backend.py b/tests/test_backend.py
new file mode 100644
index 0000000..7b6bed1
--- /dev/null
+++ b/tests/test_backend.py
@@ -0,0 +1,42 @@
+from datetime import datetime
+
+import pytest
+import pytz
+
+from todoman.model import Todo, VtodoWritter
+
+
+def test_serialize_created_at(todo_factory):
+    now = datetime.now(tz=pytz.UTC)
+    todo = todo_factory(created_at=now)
+    vtodo = VtodoWritter(todo).serialize()
+
+    assert vtodo.get('created') is not None
+
+
+def test_serialize_dtstart(todo_factory):
+    now = datetime.now(tz=pytz.UTC)
+    todo = todo_factory(start=now)
+    vtodo = VtodoWritter(todo).serialize()
+
+    assert vtodo.get('dtstart') is not None
+
+
+def test_serializer_raises(todo_factory):
+    todo = todo_factory()
+    writter = VtodoWritter(todo)
+
+    with pytest.raises(Exception):
+        writter.serialize_field('nonexistant', 7)
+
+
+def test_supported_fields_are_serializeable():
+    supported_fields = set(
+        Todo.DATETIME_FIELDS +
+        Todo.INT_FIELDS +
+        Todo.LIST_FIELDS +
+        Todo.STRING_FIELDS
+    )
+    serialized_fields = set(VtodoWritter.FIELD_MAP.keys())
+
+    assert supported_fields == serialized_fields
Repository: pimutils/todoman
Pull request #202 (2017-03-22 00:14:04)

Validate --sort fields pre-emptively


Patch:
diff --git a/todoman/cli.py b/todoman/cli.py
index df97901..3986f81 100644
--- a/todoman/cli.py
+++ b/todoman/cli.py
@@ -78,7 +78,15 @@ def _validate_start_date_param(ctx, param, val):
 
 
 def _sort_callback(ctx, param, val):
-    return val.split(',') if val else []
+    fields = val.split(',') if val else []
+    for field in fields:
+        if field.startswith('-'):
+            field = field[1:]
+
+        if field not in Todo.ALL_SUPPORTED_FIELDS and field != 'id':
+            raise click.BadParameter('Unknown field "{}"'.format(field))
+
+    return fields
 
 
 def _todo_property_options(command):
diff --git a/todoman/model.py b/todoman/model.py
index 313efbd..7abc744 100644
--- a/todoman/model.py
+++ b/todoman/model.py
@@ -165,6 +165,12 @@ class Todo:
         'start',
         'due',
     ]
+    ALL_SUPPORTED_FIELDS = (
+        DATETIME_FIELDS +
+        INT_FIELDS +
+        LIST_FIELDS +
+        STRING_FIELDS
+    )
 
     def __setattr__(self, name, value):
         # Avoids accidentally setting a field to None when that's not a valid


Test patch:
diff --git a/tests/test_backend.py b/tests/test_backend.py
index 7b6bed1..c181735 100644
--- a/tests/test_backend.py
+++ b/tests/test_backend.py
@@ -31,12 +31,7 @@ def test_serializer_raises(todo_factory):
 
 
 def test_supported_fields_are_serializeable():
-    supported_fields = set(
-        Todo.DATETIME_FIELDS +
-        Todo.INT_FIELDS +
-        Todo.LIST_FIELDS +
-        Todo.STRING_FIELDS
-    )
+    supported_fields = set(Todo.ALL_SUPPORTED_FIELDS)
     serialized_fields = set(VtodoWritter.FIELD_MAP.keys())
 
     assert supported_fields == serialized_fields
diff --git a/tests/test_cli.py b/tests/test_cli.py
index b0d8b4b..d694443 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -364,6 +364,13 @@ def test_sorting_null_values(tmpdir, runner, create):
     assert 'aaa' in result.output.splitlines()[1]
 
 
+def test_sort_invalid_fields(runner):
+    result = runner.invoke(cli, ['list', '--sort', 'hats'])
+
+    assert result.exception
+    assert 'Invalid value for "--sort": Unknown field "hats"' in result.output
+
+
 @pytest.mark.parametrize('hours', [72, -72])
 def test_color_due_dates(tmpdir, runner, create, hours):
     due = datetime.datetime.now() + datetime.timedelta(hours=hours)
Repository: pimutils/todoman
Pull request #314 (2018-07-04 11:03:47)

Add 'description' and 'modified_at' attributes to the output of --porcelain
Add 'description' and 'modified_at' attributes to the output of --porcelain.

Btw, is there a reason why we don't simply add all the attributes of Todo class to the output of porcelain?


Patch:
diff --git a/todoman/formatters.py b/todoman/formatters.py
index a1014a8..1ec179d 100644
--- a/todoman/formatters.py
+++ b/todoman/formatters.py
@@ -236,6 +236,8 @@ class PorcelainFormatter(DefaultFormatter):
             "summary": todo.summary,
             "priority": todo.priority,
             "location": todo.location,
+            "description": todo.description,
+            "completed_at": self.format_datetime(todo.completed_at),
         }
 
     def compact(self, todo):


Test patch:
diff --git a/tests/test_porcelain.py b/tests/test_porcelain.py
index 760d8ae..ede7b80 100644
--- a/tests/test_porcelain.py
+++ b/tests/test_porcelain.py
@@ -12,6 +12,7 @@ def test_list_all(tmpdir, runner, create):
         "test.ics",
         "SUMMARY:Do stuff\n"
         "STATUS:COMPLETED\n"
+        "COMPLETED:20181225T191234Z\n"
         "DUE;VALUE=DATE-TIME;TZID=CET:20160102T000000\n"
         "PERCENT-COMPLETE:26\n"
         "LOCATION:Wherever\n",
@@ -21,6 +22,8 @@ def test_list_all(tmpdir, runner, create):
     expected = [
         {
             "completed": True,
+            "completed_at": 1545765154,
+            "description": "",
             "due": 1451689200,
             "id": 1,
             "list": "default",
@@ -49,6 +52,8 @@ def test_list_due_date(tmpdir, runner, create):
     expected = [
         {
             "completed": True,
+            "completed_at": None,
+            "description": "",
             "due": 1451692800,
             "id": 1,
             "list": "default",
@@ -70,6 +75,8 @@ def test_list_nodue(tmpdir, runner, create):
     expected = [
         {
             "completed": False,
+            "completed_at": None,
+            "description": "",
             "due": None,
             "id": 1,
             "list": "default",
@@ -131,6 +138,8 @@ def test_show(tmpdir, runner, create):
 
     expected = {
         "completed": False,
+        "completed_at": None,
+        "description": "Lots of text. Yum!",
         "due": None,
         "id": 1,
         "list": "default",
@@ -150,6 +159,8 @@ def test_simple_action(todo_factory):
 
     expected = {
         "completed": False,
+        "completed_at": None,
+        "description": "",
         "due": None,
         "id": 7,
         "list": "default",
Repository: pimutils/todoman
Pull request #316 (2018-07-17 13:20:57)

Default priority
I added a ``default_priority`` value to the configuration. It is treated the same way as ``default_due``.


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 9292ffe..f1062d1 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -13,6 +13,7 @@ v3.6.0
   version.
 * ``click-repl`` is now listed as an optional dependency. It is required for
   the ``todo repl`` command.
+* Add the ``default_priority`` config setting.
 
 v3.5.0
 ------
diff --git a/todoman/cli.py b/todoman/cli.py
index 107651e..c6aa6ea 100644
--- a/todoman/cli.py
+++ b/todoman/cli.py
@@ -362,6 +362,10 @@ def new(ctx, summary, list, todo_properties, read_description, interactive):
     if default_due:
         todo.due = todo.created_at + timedelta(hours=default_due)
 
+    default_priority = ctx.config['main']['default_priority']
+    if default_priority is not None:
+        todo.priority = default_priority
+
     for key, value in todo_properties.items():
         if value:
             setattr(todo, key, value)
diff --git a/todoman/confspec.ini b/todoman/confspec.ini
index 05cf7bb..5d23733 100644
--- a/todoman/confspec.ini
+++ b/todoman/confspec.ini
@@ -51,3 +51,7 @@ startable = boolean(default=False)
 
 # When running ``todo`` with no commands, run this command.
 default_command = string(default='list')
+
+# The default priority of a task on creation.
+# Highest priority is 1, lowest priority is 10, and 0 means no priority at all.
+default_priority = integer(0, 9, default=None)


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 09c4ca1..2f83feb 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -938,3 +938,39 @@ def test_new_description_from_stdin(runner, todos):
     todo, = todos()
     assert 'world' in todo.description
     assert 'hello' in todo.summary
+
+
+def test_default_priority(tmpdir, runner, create):
+    """Test setting the due date using the default_due config parameter"""
+    path = tmpdir.join('config')
+    path.write('default_priority = 3\n', 'a')
+
+    runner.invoke(cli, ['new', '-l', 'default', 'aaa'])
+    db = Database([tmpdir.join('default')], tmpdir.join('/default_list'))
+    todo = list(db.todos())[0]
+
+    assert todo.priority == 3
+
+
+def test_no_default_priority(tmpdir, runner, create):
+    """Test setting the due date using the default_due config parameter"""
+
+    runner.invoke(cli, ['new', '-l', 'default', 'aaa'])
+
+    db = Database([tmpdir.join('default')], tmpdir.join('/default_list'))
+    todo = list(db.todos())[0]
+    assert todo.priority is 0
+
+    todo_file = tmpdir.join('default').join(todo.filename)
+    todo_ics = todo_file.read_text('utf-8')
+    assert 'PRIORITY' not in todo_ics
+
+
+def test_invalid_default_priority(tmpdir, runner, create):
+    """Test setting the due date using the default_due config parameter"""
+    path = tmpdir.join('config')
+    path.write('default_priority = 13\n', 'a')
+
+    result = runner.invoke(cli, ['new', '-l', 'default', 'aaa'])
+    assert result.exception
+    assert 'Bad default_priority setting' in result.output
Repository: pimutils/todoman
Pull request #318 (2018-07-20 17:27:49)

Fix coloring with RGBA color strings
Simple mistake preventing #rrggbbaa strings to be interpreted correctly.


Patch:
diff --git a/todoman/formatters.py b/todoman/formatters.py
index 93b7bda..9ba4c95 100644
--- a/todoman/formatters.py
+++ b/todoman/formatters.py
@@ -17,7 +17,7 @@ def rgb_to_ansi(colour):
     if not colour or not colour.startswith('#'):
         return
 
-    r, g, b = colour[1:3], colour[3:5], colour[5:8]
+    r, g, b = colour[1:3], colour[3:5], colour[5:7]
 
     if not len(r) == len(g) == len(b) == 2:
         return


Test patch:
diff --git a/tests/test_formatter.py b/tests/test_formatter.py
index ad7a046..a7de521 100644
--- a/tests/test_formatter.py
+++ b/tests/test_formatter.py
@@ -141,6 +141,6 @@ def test_formatting_parsing_consitency(default_formatter):
 def test_rgb_to_ansi():
     assert rgb_to_ansi(None) is None
     assert rgb_to_ansi('#8ab6d') is None
-    assert rgb_to_ansi('#8ab6d2f') is None
+    assert rgb_to_ansi('#8ab6d2f') == '\x1b[38;2;138;182;210m'
     assert rgb_to_ansi('red') is None
     assert rgb_to_ansi('#8ab6d2') == '\x1b[38;2;138;182;210m'
Repository: pimutils/todoman
Pull request #328 (2018-10-18 04:16:12)

Fix crash due to changes in icalendar 4.0.3
Basically, tests for master are failing due to an API change in icalendar.

This fixes that. I wonder if we need to introduce additional test around calendars, or just wait for #323.


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index b33ce41..bd34ec6 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -4,6 +4,11 @@ Changelog
 This file contains a brief summary of new features and dependency changes or
 releases, in reverse chronological order.
 
+v3.5.0
+------
+* Fix crashes due to API changes in icalendar 4.0.3.
+* Dropped compatibility for icalendar < 4.0.3.
+
 v3.4.1
 ------
 * Support Python 3.7.
diff --git a/setup.py b/setup.py
index 042d64e..9e282bd 100644
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@ setup(
         'click-log>=0.2.1',
         'configobj',
         'humanize',
-        'icalendar',
+        'icalendar>=4.0.3',
         'parsedatetime',
         'python-dateutil',
         'pyxdg',
diff --git a/todoman/model.py b/todoman/model.py
index 54c0f26..6f1bde3 100644
--- a/todoman/model.py
+++ b/todoman/model.py
@@ -284,7 +284,7 @@ class VtodoWritter:
         if name in Todo.DATETIME_FIELDS:
             return self.normalize_datetime(value)
         if name in Todo.LIST_FIELDS:
-            return ','.join(value)
+            return value
         if name in Todo.INT_FIELDS:
             return int(value)
         if name in Todo.STRING_FIELDS:
@@ -537,6 +537,13 @@ class Cache:
 
         return rrule.to_ical().decode()
 
+    def _serialize_categories(self, todo, field):
+        categories = todo.get(field, [])
+        if not categories:
+            return ''
+
+        return ','.join([str(category) for category in categories.cats])
+
     def add_vtodo(self, todo, file_path, id=None):
         """
         Adds a todo into the cache.
@@ -587,7 +594,7 @@ class Cache:
             todo.get('status', 'NEEDS-ACTION'),
             todo.get('description', None),
             todo.get('location', None),
-            todo.get('categories', None),
+            self._serialize_categories(todo, 'categories'),
             todo.get('sequence', 1),
             self._serialize_datetime(todo, 'last-modified'),
             self._serialize_rrule(todo, 'rrule'),


Test patch:
diff --git a/tests/test_backend.py b/tests/test_backend.py
index b6b0f01..95bddfe 100644
--- a/tests/test_backend.py
+++ b/tests/test_backend.py
@@ -63,7 +63,10 @@ def test_vtodo_serialization(todo_factory):
     writer = VtodoWritter(todo)
     vtodo = writer.serialize()
 
-    assert str(vtodo.get('categories')) == 'tea,drinking,hot'
+    assert (
+        [str(c) for c in vtodo.get('categories').cats] ==
+        ['tea', 'drinking', 'hot']
+    )
     assert str(vtodo.get('description')) == description
     assert vtodo.get('priority') == 7
     assert vtodo.decoded('due') == datetime(3000, 3, 21, tzinfo=tzlocal())
Repository: pimutils/todoman
Pull request #377 (2020-01-23 11:01:19)

Issue 376 porcelain date
Fix for #376 by explicitly checking for datetime.date types like the other Formatters do.

(I added myself to AUTHORS.rst in accordance with https://todoman.readthedocs.io/en/stable/contributing.html though it seems a bit much for one line!)


Patch:
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 393b170..b9c56c3 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -1,6 +1,6 @@
 name: Checks
 
-on: [push]
+on: [push, pull_request]
 
 jobs:
   styles:
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 4bccd53..53799d1 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -11,6 +11,7 @@ when copying code from elsewhere).
 Authors are listed in alphabetical order.
 
 * Anubha Agrawal <anubhakannu@gmail.com>
+* Ben Moran <github@benmoran.net>
 * Benjamin Frank <ben+gitlab@pipsfrank.de>
 * Christian Geier <geier@lostpackets.de>
 * Doron Behar <me@doronbehar.com>
diff --git a/todoman/formatters.py b/todoman/formatters.py
index 8bdd55c..cb7ad88 100644
--- a/todoman/formatters.py
+++ b/todoman/formatters.py
@@ -270,6 +270,8 @@ class PorcelainFormatter(DefaultFormatter):
 
     def format_datetime(self, date):
         if date:
+            if not hasattr(date, 'timestamp'):
+                date = datetime.datetime.fromordinal(date.toordinal())
             return int(date.timestamp())
         else:
             return None


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index c2ba4bc..eeade8c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,6 +1,6 @@
 name: Tests
 
-on: [push]
+on: [push, pull_request]
 
 jobs:
   tests:
diff --git a/tests/test_porcelain.py b/tests/test_porcelain.py
index ea8deb8..36b091d 100644
--- a/tests/test_porcelain.py
+++ b/tests/test_porcelain.py
@@ -34,6 +34,33 @@ def test_list_all(tmpdir, runner, create):
     )
 
 
+def test_list_due_date(tmpdir, runner, create):
+    create(
+        'test.ics', 'SUMMARY:Do stuff\n'
+        'STATUS:COMPLETED\n'
+        'DUE;VALUE=DATE:20160102\n'
+        'PERCENT-COMPLETE:26\n'
+        'LOCATION:Wherever\n'
+    )
+    result = runner.invoke(cli, ['--porcelain', 'list', '--status', 'ANY'])
+
+    expected = [{
+        'completed': True,
+        'due': 1451692800,
+        'id': 1,
+        'list': 'default',
+        'location': 'Wherever',
+        'percent': 26,
+        'priority': 0,
+        'summary': 'Do stuff',
+    }]
+
+    assert not result.exception
+    assert result.output.strip() == json.dumps(
+        expected, indent=4, sort_keys=True
+    )
+
+
 def test_list_nodue(tmpdir, runner, create):
     create(
         'test.ics', 'SUMMARY:Do stuff\n'
Repository: pimutils/todoman
Pull request #436 (2021-05-20 07:19:57)

pass arguments properly to invoke
The arguments being passed to invoke weren't doing anything.

Now they are properly parsed, converted (sort as list, due as integer, ...) and passed to invoke.

Example from my config file:
```
default_command = "list --sort=due --due 168 --priority low --no-reverse tasks"
```

The arguments to list would be ignored without these changes.


Patch:
diff --git a/todoman/cli.py b/todoman/cli.py
index 0bfab0a..2e43e1f 100644
--- a/todoman/cli.py
+++ b/todoman/cli.py
@@ -309,10 +309,14 @@ def cli(click_ctx, colour, porcelain, humanize, config):
 
 
 def invoke_command(click_ctx, command):
-    name, *args = command.split(" ")
+    name, *raw_args = command.split(" ")
     if name not in cli.commands:
         raise click.ClickException("Invalid setting for [default_command]")
-    click_ctx.invoke(cli.commands[name], args)
+    parser = cli.commands[name].make_parser(click_ctx)
+    opts, args, param_order = parser.parse_args(raw_args)
+    for param in param_order:
+        opts[param.name] = param.handle_parse_result(click_ctx, opts, args)[0]
+    click_ctx.invoke(cli.commands[name], *args, **opts)
 
 
 try:  # pragma: no cover


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 0557552..b2d93ac 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -2,6 +2,7 @@ import datetime
 import sys
 from os.path import exists
 from unittest import mock
+from unittest.mock import call
 from unittest.mock import patch
 
 import click
@@ -822,6 +823,9 @@ def test_invoke_command(runner, tmpdir, config):
     config.write('default_command = "flush"\n', "a")
 
     flush = mock.MagicMock()
+    parser = mock.MagicMock()
+    flush.make_parser.return_value = parser
+    parser.parse_args.return_value = {}, [], []
     with patch.dict(cli.commands, values={"flush": flush}):
         result = runner.invoke(cli, catch_exceptions=False)
 
@@ -939,3 +943,28 @@ def test_invalid_default_priority(config, runner, create):
     result = runner.invoke(cli, ["new", "-l", "default", "aaa"])
     assert result.exception
     assert "Error: Invalid `default_priority` settings." in result.output
+
+
+def test_default_command_args(config, runner):
+    config.write(
+        'default_command = "list --sort=due --due 168 ' '--priority low --no-reverse"',
+        "a",
+    )
+
+    with patch("todoman.model.Database.todos", spec=True) as todos:
+        result = runner.invoke(cli)
+
+    assert not result.exception
+    assert todos.call_args == call(
+        sort=["due"],
+        due=168,
+        priority=9,
+        reverse=False,
+        lists=[],
+        location=None,
+        category=None,
+        grep=None,
+        start=None,
+        startable=None,
+        status="NEEDS-ACTION,IN-PROCESS",
+    )