Skip to content

Fix: task operations fail when name contains #, & or +#90

Open
underwear wants to merge 1 commit into
kiblee:masterfrom
underwear:fix/odata-special-chars
Open

Fix: task operations fail when name contains #, & or +#90
underwear wants to merge 1 commit into
kiblee:masterfrom
underwear:fix/odata-special-chars

Conversation

@underwear

@underwear underwear commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Problem

complete, rm and other commands that look up a task by name fail when the task title contains #, & or +.

This happens because get_task_id_by_name puts the task name directly into an OData $filter URL:

.../tasks?$filter=title eq 'Buy groceries #shopping'
  • # — interpreted as URL fragment, everything after it is cut off
  • & — interpreted as query parameter separator, breaks the filter expression
  • + — interpreted as a space, so the filter matches the wrong title

This is a common issue because Microsoft To Do uses # for tags.

Solution

Add _escape_odata_string() helper that double-percent-encodes these characters before embedding them in the URL. For example # becomes %2523. The HTTP layer decodes one level (%23), then the OData parser decodes the second level back to #.

This approach is documented by Microsoft:
https://learn.microsoft.com/en-us/answers/questions/432875/how-do-you-escape-the-octothorpe-number-pound-hashtag-symbol-in-a-graph-api-odata-search-string

Changes

  • todocli/graphapi/wrapper.py — add _escape_odata_string(), use it in get_task_id_by_name
  • tests/test_odata_escape.py — 17 unit tests for the escaping logic and filter URL construction
  • tests/run_tests.py — register new test module

Test plan

  • All 71 unit tests pass (54 existing + 17 new)
  • Manually tested rm, complete with task names containing #, &, +
  • Task names without special characters still work as before

@underwear underwear force-pushed the fix/odata-special-chars branch 2 times, most recently from 237ff10 to 4cef583 Compare February 4, 2026 19:53
The OData $filter query in get_task_id_by_name breaks for task names
with URL-special characters:
- '#' is treated as a URL fragment identifier and truncates the query
- '&' is treated as a query parameter separator
- '+' is interpreted as a space

This is a common issue because Microsoft To Do uses '#' for tags
(e.g. "Buy groceries #shopping").

Fix: add _escape_odata_string() that double-percent-encodes these
characters before embedding them in the OData filter URL. The HTTP
layer decodes one level, and the OData parser decodes the second,
producing the correct literal character.

Reference: https://learn.microsoft.com/en-us/answers/questions/432875/how-do-you-escape-the-octothorpe-number-pound-hashtag-symbol-in-a-graph-api-odata-search-string

Includes 17 unit tests for the escaping logic and filter URL
construction.
@underwear underwear force-pushed the fix/odata-special-chars branch from 4cef583 to 3a9a247 Compare February 4, 2026 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant