pyclean.cli   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 12
eloc 99
dl 0
loc 151
rs 10
c 0
b 0
f 0

3 Functions

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