Coverage for magnetismi/cli.py: 0.00%
59 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 20:21:25 +00:00
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-04 20:21:25 +00:00
1"""Command line interface for splice (Finnish liitos) contributions."""
3import argparse
4import datetime as dti
5import sys
6from typing import List, Union
8import magnetismi.magnetismi as api
9from magnetismi import APP_ALIAS, APP_NAME, date_from_fractional_year
10from magnetismi.model.cof import YEARS_COVERED
12DATE_FORMAT = '%Y-%m-%d'
15def parse_request(argv: List[str]) -> Union[int, argparse.Namespace]:
16 """DRY."""
17 parser = argparse.ArgumentParser(
18 prog=APP_ALIAS, description=APP_NAME, formatter_class=argparse.RawTextHelpFormatter
19 )
20 parser.add_argument(
21 '--latitude',
22 dest='lat_dd',
23 type=float,
24 required=True,
25 help='geodetic latitude in decimal degrees inside [-180, +180]',
26 )
27 parser.add_argument(
28 '--longitude',
29 dest='lon_dd',
30 type=float,
31 required=True,
32 help='geodetic longitude in decimal degrees inside [-90, +90]',
33 )
34 parser.add_argument(
35 '--altitude',
36 dest='alt_ft',
37 type=float,
38 default=0,
39 help='altitude in feet inside [-3280.84, +2788714]. Optional (default: 0)',
40 )
41 parser.add_argument(
42 '--date',
43 dest='date',
44 default='',
45 help=(
46 'date for magentic calculation in YYYY-mm-dd or fractional year decimal format.'
47 ' Optional\n(default: positional date value)'
48 ),
49 required=False,
50 )
51 parser.add_argument(
52 'date_pos',
53 nargs='?',
54 default='',
55 help=(
56 'date for magentic calculation in YYYY-mm-dd or fractional year decimal format.'
57 ' Optional\n(default: empty for current date)'
58 ),
59 )
60 parser.add_argument(
61 '--quiet',
62 '-q',
63 dest='quiet',
64 default=False,
65 action='store_true',
66 help='work as quiet as possible - progress bar only if all well (default: False)',
67 )
68 parser.add_argument(
69 '--verbose',
70 '-v',
71 dest='verbose',
72 default=False,
73 action='store_true',
74 help='work logging more information along the way (default: False)',
75 )
76 if not argv:
77 parser.print_help()
78 return 0
80 options = parser.parse_args(argv)
82 if options.verbose and options.quiet:
83 parser.error('you cannot be quiet and verbose at the same time')
85 if options.date:
86 if '-' in options.date:
87 try:
88 options.date_in = dti.datetime.strptime(options.date, DATE_FORMAT).date()
89 except ValueError as err:
90 parser.error(f'requested date ({options.date}) does not parse as YYYY-mm-dd; error: {err}')
91 else:
92 try:
93 options.date_in = date_from_fractional_year(float(options.date))
94 except ValueError as err:
95 parser.error(f'requested date ({options.date}) does not parse as decimal fractional year; error: {err}')
96 else:
97 if options.date_pos:
98 if '-' in options.date_pos:
99 try:
100 options.date_in = dti.datetime.strptime(options.date_pos, DATE_FORMAT).date()
101 except ValueError as err:
102 parser.error(
103 f'requested (positional) date ({options.date_pos}) does not parse as YYYY-mm-dd; error: {err}'
104 )
105 else:
106 try:
107 options.date_in = date_from_fractional_year(float(options.date_pos))
108 except ValueError as err:
109 parser.error(
110 f'requested (positional) date ({options.date_pos})'
111 f' does not parse as decimal fractional year; error: {err}'
112 )
113 else:
114 options.date_in = dti.date.today()
116 if options.date_in.year not in YEARS_COVERED:
117 parser.error(f'requested year ({options.date_in.year}) is outside of {YEARS_COVERED}')
119 if not -3280.84 <= options.alt_ft <= 2788714.0:
120 parser.error(
121 f'requested altitude ({options.alt_ft}) is outside of [-3280.84, +2788714] feet'
122 ' and the model is only valid between the corresponding [-1, +850] km'
123 )
125 if not -90 <= options.lat_dd <= 90:
126 parser.error(f'requested latitude ({options.lat_dd}) is outside of [-90, +90] degrees')
128 if not -180 <= options.lon_dd <= 180:
129 parser.error(f'requested longitude ({options.lon_dd}) is outside of [-180, +180] degrees')
131 return options
134def main(argv: Union[List[str], None] = None) -> int:
135 """Delegate processing to functional module."""
136 argv = sys.argv[1:] if argv is None else argv
137 options = parse_request(argv)
138 if isinstance(options, int):
139 return 0
140 return api.calc(options)