things3.things3_cli.Things3CLI.print_tasks()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 31
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 27
nop 2
dl 0
loc 31
rs 8.2986
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
"""Simple read-only Thing 3 CLI."""
5
6
from __future__ import print_function
7
8
import sys
9
import argparse
10
import json
11
import csv
12
import webbrowser
13
import argcomplete  # type: ignore
14
import things3
15
from things3.things3 import Things3
16
from things3.things3_opml import Things3OPML
17
18
19
class Things3CLI:
20
    """Simple read-only Thing 3 CLI."""
21
22
    print_json = False
23
    print_csv = False
24
    print_opml = False
25
    anonymize = False
26
    things3 = None
27
28
    def __init__(self, database=None):
29
        self.things3 = Things3(database)
30
31
    def print_tasks(self, tasks):
32
        """Print a task."""
33
        if self.print_json:
34
            print(json.dumps(tasks))
35
        elif self.print_opml:
36
            Things3OPML().print_tasks(tasks)
37
        elif self.print_csv:
38
            fieldnames = [
39
                "uuid",
40
                "title",
41
                "context",
42
                "context_uuid",
43
                "size",
44
                "type",
45
                "due",
46
                "created",
47
                "modified",
48
                "started",
49
                "stopped",
50
                "notes",
51
            ]
52
            writer = csv.DictWriter(
53
                sys.stdout, fieldnames=fieldnames, delimiter=";", extrasaction="ignore"
54
            )
55
            writer.writeheader()
56
            writer.writerows(tasks)
57
        else:
58
            for task in tasks:
59
                title = task["title"]
60
                context = task["context"] if "context" in task else ""
61
                print(" - ", title, " (", context, ")")
62
63
    @classmethod
64
    def print_unimplemented(cls):
65
        """Show warning that method is not yet implemented."""
66
        print("not implemented yet (see things.sh for a more complete CLI)")
67
68
    @classmethod
69
    def get_parser(cls):
70
        """Create command line argument parser"""
71
        parser = argparse.ArgumentParser(description="Simple read-only Thing 3 CLI.")
72
73
        subparsers = parser.add_subparsers(
74
            help="", metavar="command", required=True, dest="command"
75
        )
76
        subparsers.add_parser("inbox", help="Shows inbox tasks")
77
        subparsers.add_parser("today", help="Shows todays tasks")
78
        subparsers.add_parser("upcoming", help="Shows upcoming tasks")
79
        subparsers.add_parser("next", help="Shows next tasks")
80
        subparsers.add_parser("backlog", help="Shows backlog tasks")
81
        subparsers.add_parser("completed", help="Shows completed tasks")
82
        subparsers.add_parser("cancelled", help="Shows cancelled tasks")
83
        subparsers.add_parser("trashed", help="Shows trashed tasks")
84
        subparsers.add_parser("feedback", help="Give feedback")
85
        subparsers.add_parser("all", help="Shows all tasks")
86
        subparsers.add_parser("csv", help="Exports tasks as CSV")
87
        subparsers.add_parser("areas", help="Shows all areas")
88
        subparsers.add_parser("opml", help="Exports tasks as OPML")
89
        subparsers.add_parser("due", help="Shows tasks with due dates")
90
        subparsers.add_parser("empty", help="Shows projects that are empty")
91
        subparsers.add_parser("headings", help="Shows headings")
92
        subparsers.add_parser("hours", help="Shows hours planned today")
93
        subparsers.add_parser("ical", help="Shows tasks ordered by due date as iCal")
94
        subparsers.add_parser("lint", help="Shows tasks that float around")
95
        subparsers.add_parser("logbook", help="Shows tasks completed today")
96
        subparsers.add_parser(
97
            "mostClosed", help="Shows days when most tasks were closed"
98
        )
99
        subparsers.add_parser(
100
            "mostCancelled", help="Shows days when most tasks were cancelled"
101
        )
102
        subparsers.add_parser(
103
            "mostTrashed", help="Shows days when most tasks were trashed"
104
        )
105
        subparsers.add_parser(
106
            "mostCreated", help="Shows days when most tasks were created"
107
        )
108
        subparsers.add_parser("mostTasks", help="Shows projects that have most tasks")
109
        subparsers.add_parser(
110
            "mostCharacters", help="Shows tasks that have most characters"
111
        )
112
        subparsers.add_parser("nextish", help="Shows all nextish tasks")
113
        subparsers.add_parser("old", help="Shows all old tasks")
114
        subparsers.add_parser("projects", help="Shows all projects")
115
        subparsers.add_parser("repeating", help="Shows all repeating tasks")
116
        subparsers.add_parser("schedule", help="Schedules an event using a template")
117
        subparsers.add_parser("search", help="Searches for a specific task")
118
        subparsers.add_parser("stat", help="Provides a number of statistics")
119
        subparsers.add_parser("statcsv", help="Exports some statistics as CSV")
120
        subparsers.add_parser("subtasks", help="Shows all subtasks")
121
        subparsers.add_parser("tag", help="Shows all tasks with the waiting for tag")
122
        subparsers.add_parser("tags", help="Shows all tags ordered by their usage")
123
        subparsers.add_parser(
124
            "waiting", help="Shows all tasks with the waiting for tag"
125
        )
126
127
        parser.add_argument(
128
            "-j",
129
            "--json",
130
            action="store_true",
131
            default=False,
132
            help="output as JSON",
133
            dest="json",
134
        )
135
136
        parser.add_argument(
137
            "-c",
138
            "--csv",
139
            action="store_true",
140
            default=False,
141
            help="output as CSV",
142
            dest="csv",
143
        )
144
145
        parser.add_argument(
146
            "-o",
147
            "--opml",
148
            action="store_true",
149
            default=False,
150
            help="output as OPML",
151
            dest="opml",
152
        )
153
154
        parser.add_argument(
155
            "-a",
156
            "--anonymize",
157
            action="store_true",
158
            default=False,
159
            help="anonymize output",
160
            dest="anonymize",
161
        )
162
163
        parser.add_argument(
164
            "--version",
165
            action="version",
166
            version=f"%(prog)s (version {things3.__version__})",
167
        )
168
169
        argcomplete.autocomplete(parser)
170
171
        return parser
172
173
    def main(self, args=None):
174
        """Main entry point of the app"""
175
176
        if args is None:
177
            self.main(Things3CLI.get_parser().parse_args())
178
        else:
179
            command = args.command
180
            self.print_json = args.json
181
            self.print_csv = args.csv
182
            self.print_opml = args.opml
183
            self.anonymize = args.anonymize
184
            self.things3.anonymize = self.anonymize
185
186
            if command in self.things3.functions:
187
                func = self.things3.functions[command]
188
                self.print_tasks(func(self.things3))
189
            elif command == "opml":
190
                Things3OPML().print_all(self.things3)
191
            elif command == "csv":
192
                print("Deprecated: use --csv instead")
193
            elif command == "feedback":
194
                webbrowser.open("https://github.com/AlexanderWillner/KanbanView/issues")
195
            else:
196
                Things3CLI.print_unimplemented()
197
198
199
def main():
200
    """Main entry point for CLI installation"""
201
    Things3CLI().main()
202
203
204
if __name__ == "__main__":
205
    main()
206