cctodo 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cctodo-0.1.0/LICENSE +21 -0
- cctodo-0.1.0/PKG-INFO +110 -0
- cctodo-0.1.0/README.md +93 -0
- cctodo-0.1.0/pyproject.toml +33 -0
- cctodo-0.1.0/setup.cfg +4 -0
- cctodo-0.1.0/src/cctodo/__init__.py +10 -0
- cctodo-0.1.0/src/cctodo/__main__.py +3 -0
- cctodo-0.1.0/src/cctodo/cli.py +569 -0
- cctodo-0.1.0/src/cctodo/client.py +315 -0
- cctodo-0.1.0/src/cctodo/config.py +64 -0
- cctodo-0.1.0/src/cctodo/errors.py +63 -0
- cctodo-0.1.0/src/cctodo.egg-info/PKG-INFO +110 -0
- cctodo-0.1.0/src/cctodo.egg-info/SOURCES.txt +16 -0
- cctodo-0.1.0/src/cctodo.egg-info/dependency_links.txt +1 -0
- cctodo-0.1.0/src/cctodo.egg-info/entry_points.txt +2 -0
- cctodo-0.1.0/src/cctodo.egg-info/top_level.txt +1 -0
- cctodo-0.1.0/tests/test_cli.py +93 -0
- cctodo-0.1.0/tests/test_client.py +78 -0
cctodo-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CloudCircus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cctodo-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cctodo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Command line tool and Python client for ccToDo (www.cctodo.com)
|
|
5
|
+
Author-email: CloudCircus <support@cctodo.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://www.cctodo.com/
|
|
8
|
+
Project-URL: Source, https://github.com/RubenNorgaard/cctodo_py
|
|
9
|
+
Keywords: todo,tasks,cli,cctodo
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Office/Business :: Scheduling
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# cctodo
|
|
19
|
+
|
|
20
|
+
The command line tool and Python client for [ccToDo](https://www.cctodo.com/), made by CloudCircus.
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
pip install cctodo
|
|
24
|
+
cctodo login # paste a token from Settings → API tokens
|
|
25
|
+
cctodo mytasks
|
|
26
|
+
cctodo new -group "work group" "my task"
|
|
27
|
+
cctodo done 123
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It uses only the Python standard library and needs Python 3.9 or newer.
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
Tasks are shown with their id (`#123`), and the commands take that id. Where a command takes a group,
|
|
35
|
+
you can give its id, its title, or the start of the title (case-insensitive). Without `-g`, commands
|
|
36
|
+
use your **My Tasks**.
|
|
37
|
+
|
|
38
|
+
| Command | What it does |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `cctodo mytasks` (`my`) | Your pending My Tasks. `-c` shows completed tasks instead. |
|
|
41
|
+
| `cctodo list [GROUP]` (`ls`) | A group's pending tasks. `--all` lists every group, `-c` shows completed tasks. |
|
|
42
|
+
| `cctodo assigned` | Pending tasks assigned to you, in all groups. |
|
|
43
|
+
| `cctodo groups` | Your groups, with their pending counts. |
|
|
44
|
+
| `cctodo new TITLE… [-g GROUP] [-a WHO] [-b BODY] [-e]` (`add`) | Adds a task at the bottom of the list. `-b -` reads the details from stdin; `-e` writes the title and details in `$EDITOR`. |
|
|
45
|
+
| `cctodo show ID` | A task with its details (markdown) and comments. |
|
|
46
|
+
| `cctodo done ID…` / `start ID…` / `reopen ID…` | Sets the state to done, in progress, or to do. |
|
|
47
|
+
| `cctodo edit ID [-t TITLE] [-b BODY]` | Edits a task. With no options it opens `$EDITOR`: the first line is the title and the rest is the details. It refuses to overwrite someone else's newer edit. |
|
|
48
|
+
| `cctodo assign ID WHO` | Assigns to `me`, a member's email, or `none`. |
|
|
49
|
+
| `cctodo mv ID -g GROUP` / `mv ID --before ID2` / `--after ID2` | Moves a task to another group, or reorders it. |
|
|
50
|
+
| `cctodo rm ID… [-y]` | Deletes tasks after asking you to confirm. |
|
|
51
|
+
| `cctodo comment ID TEXT… [-r COMMENT_ID]` | Adds a comment, or a reply with `-r`. |
|
|
52
|
+
| `cctodo group new/rename/members/leave/rm` | Manages groups. |
|
|
53
|
+
| `cctodo invite GROUP EMAIL [-m MESSAGE]` | Invites someone. If you're a member rather than an owner, an owner approves the invite first. |
|
|
54
|
+
| `cctodo invites` / `accept ID` / `decline ID` | Lists and answers invites addressed to you. |
|
|
55
|
+
| `cctodo whoami` / `logout` | Shows the account you're logged in as, or forgets the saved token. |
|
|
56
|
+
|
|
57
|
+
Add `--json` to any command for the raw API output. `NO_COLOR` turns colours off.
|
|
58
|
+
|
|
59
|
+
**Exit codes:**
|
|
60
|
+
- `0`: the command succeeded.
|
|
61
|
+
- `1`: an error occurred.
|
|
62
|
+
- `3`: you're not logged in, or your token was revoked.
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
`cctodo login` saves the token in `~/.config/cctodo/config.json`, readable only by you
|
|
67
|
+
(`%APPDATA%\cctodo\config.json` on Windows). You can set these environment variables instead:
|
|
68
|
+
|
|
69
|
+
- `CCTODO_TOKEN`: the API token.
|
|
70
|
+
- `CCTODO_API_URL`: the API address. It defaults to `https://api.cctodo.com`.
|
|
71
|
+
- `CCTODO_CONFIG`: a different config file.
|
|
72
|
+
|
|
73
|
+
To revoke a token, go to Settings → API tokens on www.cctodo.com.
|
|
74
|
+
|
|
75
|
+
## Python
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from cctodo import Client, Conflict
|
|
79
|
+
|
|
80
|
+
todo = Client() # the same token as the CLI (or Client(token="cct_..."))
|
|
81
|
+
work = todo.find_group("work group")
|
|
82
|
+
task = todo.create_task(work.id, "Write the report", body="Due **Friday**")
|
|
83
|
+
todo.assign(task.id, todo.me().id)
|
|
84
|
+
todo.start(task.id)
|
|
85
|
+
|
|
86
|
+
for t in todo.tasks(work.id): # pending tasks, in order
|
|
87
|
+
print(t.id, t.state, t.title) # attribute or t["title"] access
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
todo.update_task(task.id, body="…", expected_updated_at=task.updated_at)
|
|
91
|
+
except Conflict:
|
|
92
|
+
print("Someone else changed it first")
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Return values:** results are the API's JSON as `Record` objects (dicts with attribute access).
|
|
96
|
+
|
|
97
|
+
**Errors:** errors raise `cctodo.NotFound` (404; this also covers groups you're not in), `NotAllowed` (403),
|
|
98
|
+
`Invalid` (400), `Conflict` (409), `RateLimited` (429) or `Unauthorized` (401). All of them subclass `cctodo.CctodoError`.
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
pip install -e .
|
|
104
|
+
python -m unittest discover -s . -t .
|
|
105
|
+
CCTODO_API_URL=http://api.localhost:8000 cctodo whoami # against a local cctodo_web
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Licence
|
|
109
|
+
|
|
110
|
+
MIT. See [LICENSE](LICENSE).
|
cctodo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# cctodo
|
|
2
|
+
|
|
3
|
+
The command line tool and Python client for [ccToDo](https://www.cctodo.com/), made by CloudCircus.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
pip install cctodo
|
|
7
|
+
cctodo login # paste a token from Settings → API tokens
|
|
8
|
+
cctodo mytasks
|
|
9
|
+
cctodo new -group "work group" "my task"
|
|
10
|
+
cctodo done 123
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
It uses only the Python standard library and needs Python 3.9 or newer.
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
Tasks are shown with their id (`#123`), and the commands take that id. Where a command takes a group,
|
|
18
|
+
you can give its id, its title, or the start of the title (case-insensitive). Without `-g`, commands
|
|
19
|
+
use your **My Tasks**.
|
|
20
|
+
|
|
21
|
+
| Command | What it does |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `cctodo mytasks` (`my`) | Your pending My Tasks. `-c` shows completed tasks instead. |
|
|
24
|
+
| `cctodo list [GROUP]` (`ls`) | A group's pending tasks. `--all` lists every group, `-c` shows completed tasks. |
|
|
25
|
+
| `cctodo assigned` | Pending tasks assigned to you, in all groups. |
|
|
26
|
+
| `cctodo groups` | Your groups, with their pending counts. |
|
|
27
|
+
| `cctodo new TITLE… [-g GROUP] [-a WHO] [-b BODY] [-e]` (`add`) | Adds a task at the bottom of the list. `-b -` reads the details from stdin; `-e` writes the title and details in `$EDITOR`. |
|
|
28
|
+
| `cctodo show ID` | A task with its details (markdown) and comments. |
|
|
29
|
+
| `cctodo done ID…` / `start ID…` / `reopen ID…` | Sets the state to done, in progress, or to do. |
|
|
30
|
+
| `cctodo edit ID [-t TITLE] [-b BODY]` | Edits a task. With no options it opens `$EDITOR`: the first line is the title and the rest is the details. It refuses to overwrite someone else's newer edit. |
|
|
31
|
+
| `cctodo assign ID WHO` | Assigns to `me`, a member's email, or `none`. |
|
|
32
|
+
| `cctodo mv ID -g GROUP` / `mv ID --before ID2` / `--after ID2` | Moves a task to another group, or reorders it. |
|
|
33
|
+
| `cctodo rm ID… [-y]` | Deletes tasks after asking you to confirm. |
|
|
34
|
+
| `cctodo comment ID TEXT… [-r COMMENT_ID]` | Adds a comment, or a reply with `-r`. |
|
|
35
|
+
| `cctodo group new/rename/members/leave/rm` | Manages groups. |
|
|
36
|
+
| `cctodo invite GROUP EMAIL [-m MESSAGE]` | Invites someone. If you're a member rather than an owner, an owner approves the invite first. |
|
|
37
|
+
| `cctodo invites` / `accept ID` / `decline ID` | Lists and answers invites addressed to you. |
|
|
38
|
+
| `cctodo whoami` / `logout` | Shows the account you're logged in as, or forgets the saved token. |
|
|
39
|
+
|
|
40
|
+
Add `--json` to any command for the raw API output. `NO_COLOR` turns colours off.
|
|
41
|
+
|
|
42
|
+
**Exit codes:**
|
|
43
|
+
- `0`: the command succeeded.
|
|
44
|
+
- `1`: an error occurred.
|
|
45
|
+
- `3`: you're not logged in, or your token was revoked.
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
`cctodo login` saves the token in `~/.config/cctodo/config.json`, readable only by you
|
|
50
|
+
(`%APPDATA%\cctodo\config.json` on Windows). You can set these environment variables instead:
|
|
51
|
+
|
|
52
|
+
- `CCTODO_TOKEN`: the API token.
|
|
53
|
+
- `CCTODO_API_URL`: the API address. It defaults to `https://api.cctodo.com`.
|
|
54
|
+
- `CCTODO_CONFIG`: a different config file.
|
|
55
|
+
|
|
56
|
+
To revoke a token, go to Settings → API tokens on www.cctodo.com.
|
|
57
|
+
|
|
58
|
+
## Python
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from cctodo import Client, Conflict
|
|
62
|
+
|
|
63
|
+
todo = Client() # the same token as the CLI (or Client(token="cct_..."))
|
|
64
|
+
work = todo.find_group("work group")
|
|
65
|
+
task = todo.create_task(work.id, "Write the report", body="Due **Friday**")
|
|
66
|
+
todo.assign(task.id, todo.me().id)
|
|
67
|
+
todo.start(task.id)
|
|
68
|
+
|
|
69
|
+
for t in todo.tasks(work.id): # pending tasks, in order
|
|
70
|
+
print(t.id, t.state, t.title) # attribute or t["title"] access
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
todo.update_task(task.id, body="…", expected_updated_at=task.updated_at)
|
|
74
|
+
except Conflict:
|
|
75
|
+
print("Someone else changed it first")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Return values:** results are the API's JSON as `Record` objects (dicts with attribute access).
|
|
79
|
+
|
|
80
|
+
**Errors:** errors raise `cctodo.NotFound` (404; this also covers groups you're not in), `NotAllowed` (403),
|
|
81
|
+
`Invalid` (400), `Conflict` (409), `RateLimited` (429) or `Unauthorized` (401). All of them subclass `cctodo.CctodoError`.
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
pip install -e .
|
|
87
|
+
python -m unittest discover -s . -t .
|
|
88
|
+
CCTODO_API_URL=http://api.localhost:8000 cctodo whoami # against a local cctodo_web
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Licence
|
|
92
|
+
|
|
93
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cctodo"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Command line tool and Python client for ccToDo (www.cctodo.com)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
authors = [{ name = "CloudCircus", email = "support@cctodo.com" }]
|
|
14
|
+
keywords = ["todo", "tasks", "cli", "cctodo"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Topic :: Office/Business :: Scheduling",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [] # standard library only
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://www.cctodo.com/"
|
|
24
|
+
Source = "https://github.com/RubenNorgaard/cctodo_py"
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
cctodo = "cctodo.cli:main"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.dynamic]
|
|
30
|
+
version = { attr = "cctodo.__version__" }
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["src"]
|
cctodo-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Command line tool and Python client for ccToDo (https://www.cctodo.com/)."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
|
|
5
|
+
from .client import DONE, IN_PROGRESS, TODO, Client, Record # noqa: E402
|
|
6
|
+
from .errors import (ApiError, CctodoError, ConfigError, Conflict, ConnectionFailed, Invalid, # noqa: E402
|
|
7
|
+
NotAllowed, NotFound, RateLimited, Unauthorized)
|
|
8
|
+
|
|
9
|
+
__all__ = ["Client", "Record", "TODO", "IN_PROGRESS", "DONE", "CctodoError", "ApiError", "ConfigError",
|
|
10
|
+
"ConnectionFailed", "Unauthorized", "NotAllowed", "NotFound", "Invalid", "Conflict", "RateLimited"]
|