Coverage for etiketti/cli.py: 92.06%
45 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 17:54:24 +00:00
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 17:54:24 +00:00
1"""Command line interface for labeling."""
3import argparse
4import pathlib
5import sys
6from typing import Union
8import etiketti.implementation as impl
9from etiketti import (
10 APP_ALIAS,
11 APP_NAME,
12 APP_VERSION,
13 CONFIG_PATH_STRING,
14 SOURCE_NAME_PATH_STRING,
15 TARGET_NAME_PATH_STRING,
16 parse_key_value_pair_csl,
17)
20def parse_request(argv: list[str]) -> Union[int, argparse.Namespace]:
21 """DRY."""
22 parser = argparse.ArgumentParser(
23 prog=APP_ALIAS, description=APP_NAME, formatter_class=argparse.RawTextHelpFormatter
24 )
25 parser.add_argument(
26 '--in-path',
27 '-i',
28 dest='in_pdf',
29 default='',
30 help='input file path to pdf file to label',
31 required=False,
32 )
33 parser.add_argument(
34 'in_pdf_pos',
35 nargs='?',
36 default=SOURCE_NAME_PATH_STRING,
37 help='input file path to pdf file to label',
38 )
39 parser.add_argument(
40 '--out-path',
41 '-o',
42 dest='out_pdf',
43 default=TARGET_NAME_PATH_STRING,
44 help='output path for resulting labeled pdf file',
45 required=False,
46 )
47 parser.add_argument(
48 '--config',
49 '-c',
50 dest='cfg_path',
51 default=CONFIG_PATH_STRING,
52 help='configuration file for label context data',
53 required=False,
54 )
55 parser.add_argument(
56 '--enforce',
57 '-e',
58 dest='enforce',
59 default=False,
60 action='store_true',
61 help='enforce labels by overwriting the source file',
62 required=False,
63 )
64 parser.add_argument(
65 '--version',
66 '-V',
67 dest='version_request',
68 default=False,
69 action='store_true',
70 help='show version of the app and exit',
71 required=False,
72 )
73 parser.add_argument(
74 '--key-value-pairs',
75 '-k',
76 dest='key_value_pair_csl',
77 default='',
78 help='key value pairs as comma separated list of key=value pairs (default: empty string)',
79 )
81 if not argv:
82 print(f'{APP_NAME} version {APP_VERSION}')
83 parser.print_help()
84 return 0
86 options = parser.parse_args(argv)
88 if options.version_request: 88 ↛ 89line 88 didn't jump to line 89, because the condition on line 88 was never true
89 print(f'{APP_NAME} version {APP_VERSION}')
90 return 0
92 if not options.in_pdf:
93 if options.in_pdf_pos: 93 ↛ 96line 93 didn't jump to line 96, because the condition on line 93 was never false
94 options.in_pdf = options.in_pdf_pos
95 else:
96 options.in_pdf = SOURCE_NAME_PATH_STRING
98 options.kv_pairs = parse_key_value_pair_csl(options.key_value_pair_csl)
100 in_pdf = pathlib.Path(options.in_pdf)
101 if in_pdf.exists():
102 if in_pdf.is_file():
103 cfg_path = pathlib.Path(options.cfg_path)
104 if cfg_path.exists():
105 if cfg_path.is_file():
106 return options
107 parser.error(f'configuration path ({cfg_path}) is not a file')
108 parser.error(f'configuration path ({cfg_path}) does not exist')
109 parser.error(f'requested pdf at ({in_pdf}) is not a file')
110 parser.error(f'requested pdf at ({in_pdf}) does not exist')
113def app(argv: list[str] | None = None) -> int:
114 """Delegate processing to functional module."""
115 argv = sys.argv[1:] if argv is None else argv
116 options = parse_request(argv)
117 if isinstance(options, int):
118 return 0
119 return impl.patch(options)