Coverage for taksonomia/cli.py: 88.75%
54 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 23:02:14 +00:00
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 23:02:14 +00:00
1"""CLI operations for taxonomy (Finnish: taksonomia) of a folder tree, guided by conventions."""
3import argparse
4import pathlib
5import sys
6from typing import List, Union
8import taksonomia.taksonomia as api
9from taksonomia import APP_ALIAS, APP_NAME, APP_VERSION, KNOWN_FORMATS, KNOWN_KEY_FUNCTIONS, parse_csl
12def parse_request(argv: List[str]) -> Union[int, argparse.Namespace]:
13 """DRY."""
14 parser = argparse.ArgumentParser(
15 prog=APP_ALIAS, description=APP_NAME, formatter_class=argparse.RawTextHelpFormatter
16 )
17 parser.add_argument(
18 '--tree-root',
19 '-t',
20 dest='tree_root',
21 default='',
22 help='Root of the tree to visit. Optional\n(default: positional tree root value)',
23 required=False,
24 )
25 parser.add_argument(
26 'tree_root_pos', nargs='?', default='', help='Root of the tree to visit. Optional (default: PWD)'
27 )
28 parser.add_argument(
29 '--excludes',
30 '-x',
31 dest='excludes',
32 default='',
33 help='comma separated list of values to exclude paths\ncontaining the substring (default: empty string)',
34 )
35 parser.add_argument(
36 '--key-function',
37 '-k',
38 dest='key_function',
39 default='blake2',
40 help=(
41 'key function (blake2, elf, md5) for branches and leaves\n'
42 '(default: blake2) use elf only for very small taxonomies'
43 ),
44 )
45 parser.add_argument(
46 '--out-path',
47 '-o',
48 dest='out_path',
49 default=sys.stdout,
50 help='output file path (stem) for taxonomy (default: STDOUT)',
51 )
52 parser.add_argument(
53 '--formats',
54 '-f',
55 dest='format_type_csl',
56 default='json',
57 help='formats (json, xml, yaml) as comma separated list for taxonomy (default: json)',
58 )
59 parser.add_argument(
60 '--base64-encode',
61 '-e',
62 dest='base64_encode',
63 default=False,
64 action='store_true',
65 help='encode taxonomy in base64 (default: False)\nincompatible with option --xz-compress',
66 )
67 parser.add_argument(
68 '--xz-compress',
69 '-c',
70 dest='xz_compress',
71 default=False,
72 action='store_true',
73 help='compress taxonomy per LZMA(xz) (default: False)\nincompatible with option --base64-encode',
74 )
75 parser.add_argument(
76 '--version',
77 '-V',
78 dest='version_request',
79 default=False,
80 action='store_true',
81 help='show version of the app and exit',
82 required=False,
83 )
85 if not argv:
86 print(f'{APP_NAME} version {APP_VERSION}')
87 parser.print_help()
88 return 0
90 options = parser.parse_args(argv)
92 if options.version_request: 92 ↛ 93line 92 didn't jump to line 93, because the condition on line 92 was never true
93 print(f'{APP_NAME} version {APP_VERSION}')
94 return 0
96 if not options.tree_root:
97 if options.tree_root_pos: 97 ↛ 100line 97 didn't jump to line 100, because the condition on line 97 was never false
98 options.tree_root = options.tree_root_pos
99 else:
100 options.tree_root = str(pathlib.Path.cwd())
102 if options.key_function.lower() not in KNOWN_KEY_FUNCTIONS:
103 parser.error(
104 f'requested key function {options.key_function} for branches and leaves not in {KNOWN_KEY_FUNCTIONS}'
105 )
107 format_types = parse_csl(options.format_type_csl)
108 channel_count = len(format_types)
109 for fmt in format_types:
110 if fmt not in KNOWN_FORMATS:
111 parser.error(f'requested format {fmt} for taxonomy dump not in {KNOWN_FORMATS}')
113 if options.out_path is sys.stdout and channel_count > 1: 113 ↛ 114line 113 didn't jump to line 114, because the condition on line 113 was never true
114 parser.error('writing multiple formats to STDOUT is not supported.')
116 if options.base64_encode and options.xz_compress:
117 parser.error('the options --base64-encode and --xz-compress are mutually exclusive.')
119 if options.xz_compress and options.out_path is sys.stdout:
120 parser.error('compression for now not supported for standard output (only for files)')
122 tree_root = pathlib.Path(options.tree_root)
123 if tree_root.exists():
124 if tree_root.is_dir():
125 return options
126 parser.error(f'requested tree root at ({tree_root}) is not a folder')
128 parser.error(f'requested tree root at ({tree_root}) does not exist')
131def main(argv: Union[List[str], None] = None) -> int:
132 """Delegate processing to functional module."""
133 argv = sys.argv[1:] if argv is None else argv
134 options = parse_request(argv)
135 if isinstance(options, int): 135 ↛ 136line 135 didn't jump to line 136, because the condition on line 135 was never true
136 return 0
137 return api.main(options)