Passed
Pull Request — main (#81)
by Peter
01:12
created

pyclean.cli   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 12
eloc 97
dl 0
loc 142
rs 10
c 0
b 0
f 0

3 Functions

Rating   Name   Duplication   Size   Complexity  
C parse_arguments() 0 106 7
A main() 0 10 2
A init_logging() 0 9 3
1
"""
2
Command line interface implementation for pyclean.
3
"""
4
import argparse
5
import logging
6
import sys
7
8
from . import __version__, compat, modern
9
10
log = logging.getLogger(__name__)
11
12
13
def parse_arguments():
14
    """
15
    Parse and handle CLI arguments.
16
    """
17
    debris_default_topics = ['cache', 'coverage', 'package', 'pytest', 'ruff']
18
    debris_optional_topics = ['jupyter', 'mypy', 'tox']
19
    debris_choices = ['all', *debris_default_topics, *debris_optional_topics]
20
    ignore_default_items = [
21
        '.git',
22
        '.hg',
23
        '.svn',
24
        '.tox',
25
        '.venv',
26
        'node_modules',
27
        'venv',
28
    ]
29
30
    parser = argparse.ArgumentParser(
31
        description='Remove byte-compiled files for a package or project.',
32
    )
33
34
    if sys.version_info < (3, 8):
35
        parser.register('action', 'extend', compat.ExtendAction)
36
37
    parser.add_argument('--version', action='version', version=__version__)
38
    parser.add_argument(
39
        'directory',
40
        nargs='+',
41
        help='directory tree to traverse for byte-code',
42
    )
43
    parser.add_argument(
44
        '-i',
45
        '--ignore',
46
        metavar='DIRECTORY',
47
        action='extend',
48
        nargs='+',
49
        default=ignore_default_items,
50
        help='directory that should be ignored (may be specified multiple times;'
51
        ' default: %s)' % ' '.join(ignore_default_items),
52
    )
53
    parser.add_argument(
54
        '-d',
55
        '--debris',
56
        metavar='TOPIC',
57
        action='extend',
58
        nargs='*',
59
        default=argparse.SUPPRESS,
60
        choices=debris_choices,
61
        help='remove leftovers from popular Python development tools'
62
        ' (may be specified multiple times; optional: all %s; default: %s)'
63
        % (
64
            ' '.join(debris_optional_topics),
65
            ' '.join(debris_default_topics),
66
        ),
67
    )
68
    parser.add_argument(
69
        '-e',
70
        '--erase',
71
        metavar='PATTERN',
72
        action='extend',
73
        nargs='+',
74
        default=[],
75
        help='delete files or folders matching a globbing pattern (may be specified'
76
        ' multiple times); this will be interactive unless --yes is used.',
77
    )
78
    parser.add_argument(
79
        '-n',
80
        '--dry-run',
81
        action='store_true',
82
        help='show what would be done',
83
    )
84
85
    verbosity = parser.add_mutually_exclusive_group()
86
    verbosity.add_argument('-q', '--quiet', action='store_true', help='be quiet')
87
    verbosity.add_argument(
88
        '-v',
89
        '--verbose',
90
        action='store_true',
91
        help='be more verbose',
92
    )
93
94
    parser.add_argument(
95
        '-y',
96
        '--yes',
97
        action='store_true',
98
        help='assume yes as answer for interactive questions',
99
    )
100
101
    args = parser.parse_args()
102
    init_logging(args)
103
104
    if args.yes and not args.erase:
105
        parser.error('Specifying --yes only makes sense with --erase.')
106
107
    if 'debris' in args:
108
        if 'all' in args.debris:
109
            args.debris = debris_default_topics + debris_optional_topics
110
        elif not args.debris:
111
            args.debris = debris_default_topics
112
        log.debug('Debris topics to scan for: %s', ' '.join(args.debris))
113
    else:
114
        args.debris = []
115
116
    log.debug('Ignored directories: %s', ' '.join(args.ignore))
117
118
    return args
119
120
121
def init_logging(args):
122
    """
123
    Set the log level according to the -v/-q command line options.
124
    """
125
    log_level = (
126
        logging.FATAL if args.quiet else logging.DEBUG if args.verbose else logging.INFO
127
    )
128
    log_format = '%(message)s'
129
    logging.basicConfig(level=log_level, format=log_format)
130
131
132
def main():
133
    """
134
    Entry point for CLI application.
135
    """
136
    args = parse_arguments()
137
138
    try:
139
        modern.pyclean(args)
140
    except Exception as err:
141
        raise SystemExit(err)
142