Passed
Push — master ( 6f7451...c395bc )
by Alexander
05:14
created

things3.things3_cli.Things3CLI.main()   B

Complexity

Conditions 6

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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