1#!/usr/bin/env python3
2
3"""Examine table, field and calibration definitions.
4
5See also srdb_tool and packet_tool.
6
7Features:
8
9- Examine list and full descriptions of tables
10 - including filtering and per-SID information
11- Examine list and full descriptions of fields
12- Examine list and full descriptions of calibrations
13
14"""
15
16import sys
17import logging
18
19from chart.common.args import ArgumentParser
20from chart.common.prettyprint import Table
21from chart.project import SID
22from chart.common.matcher import StringTest
23from chart.db.model.calibration import PolyCalibration
24from chart.db.model.calibration import LinearCalibration
25from chart.db.model.calibration import SQLCalibration
26
27logger = logging.getLogger()
28
29INDENT = ' '
30
31def list_tables(tables, target=sys.stdout):
32 result = Table(headings=('Name', 'Fields', 'Description'))
33 for table in tables:
34 result.append((table.name, len(table.fields), table.description))
35
36 result.write()
37
38def extract_fields(tables):
39 result = set()
40 for table in tables:
41 for field in table.fields.values():
42 result.add(field)
43
44 return result
45
46def list_fields(fields):
47 result = Table(headings=('Name', 'Table', 'Calibration', 'Description'))
48 for field in fields:
49 result.append((field.name, field.table.name, field.calibration_name, field.description))
50
51 result.write()
52
53def find_fields(fields,
54 field_name=None,
55 cal_name=None):
56 """Yield only `fields` members matching criteria.
57
58 Args:
59 `fields` (list of FieldInfo): Master list to filter.
60 `field_name` (StringTest): Look for fields with matching name.
61 `cal_name` (StringTest): Look for fields with matching calibration name.
62 """
63 tests = []
64 if field_name is not None:
65 tests.append('name {t}'.format(t=field_name))
66
67 if cal_name is not None:
68 tests.append('calname {t}'.format(t=cal_name))
69
70 if len(tests) > 0:
71 logger.info('Filtering fields for {t}'.format(t=' and '.join(tests)))
72
73 for field in fields:
74 if field_name is not None and not field_name.matches(field.name):
75 continue
76
77 elif cal_name is not None and not cal_name.matches(field.calibration_name):
78 continue
79
80 yield field
81
82
83def show_fields(fields, target=sys.stdout):
84 for field in fields:
85 target.write("""Field {name}:
86{i}Description: {desc}
87{i}Datatype: {datatype}
88{i}Length: {length}
89{i}Calibration name: {cal}
90""".format(i=INDENT,
91 name=field.name,
92 desc=field.description,
93 datatype=field.datatype.value,
94 length=field.length,
95 cal=field.calibration_name))
96
97 if field.cal is not None:
98 target.write('{i}Calibrations:\n'.format(i=INDENT))
99 for sid in field.cal.sids():
100 target.write('{i}{i}{sid}:\n'.format(i=INDENT, sid=sid))
101 cal = field.cal[sid]
102 if isinstance(cal, PolyCalibration):
103 target.write('{i}{i}{i}Polynomial:\n'.format(i=INDENT))
104
105 elif isinstance(cal, LinearCalibration):
106 target.write('{i}{i}{i}Linear:\n'.format(i=INDENT))
107 for pair in cal.pairs:
108 target.write('{ii}{raw}: {cal}\n'.format(
109 ii=INDENT * 4, raw=pair.raw, cal=pair.cal))
110
111 elif isinstance(cal, SQLCalibration):
112 target.write('{i}{i}{i}SQL:\n'.format(i=INDENT))
113
114 else:
115 assert False
116
117
118
119def main():
120 """Command line entry point"""
121 parser = ArgumentParser(__doc__)
122 parser.add_argument('--list-tables',
123 action='store_true',
124 help='Show all timeseries tables')
125 parser.add_argument('--list-fields',
126 action='store_true',
127 help='List fields')
128 parser.add_argument('--show-fields',
129 action='store_true',
130 help='Show information about selected field(s)')
131 parser.add_argument('--sys',
132 action='store_true',
133 help='Switch table processing to sys tables instead of timeseries')
134 parser.add_argument('--field-name',
135 help='Filter to only matching named fields')
136 parser.add_argument('--cal-name',
137 help='Filter for only fields using named calibration')
138 args = parser.parse_args()
139
140 if args.sys:
141 raise NotImplementedError("This code needs to be revisited: '{code}' : '{error}'".format(code='tables = project.all_sys_tables()', error='project is undefined'))
142 # tables = project.all_sys_tables()
143
144 else:
145 tables = SID().all_tables()
146
147 fields = extract_fields(tables)
148
149 if args.list_tables:
150 list_tables(tables)
151 parser.exit()
152
153 fields = find_fields(
154 fields,
155 field_name=StringTest(args.field_name),
156 cal_name=StringTest(args.cal_name))
157
158 if args.list_fields:
159 list_fields(fields)
160 parser.exit()
161
162 if args.show_fields:
163 show_fields(fields)
164 parser.exit()
165
166 parser.error('No actions specified')