def _getinfo(self): "get information paragraph" self.get_ctrlvars() out = [] xtype = self._args['typefull'] mod_map = { 'enum': ca.enum_types, 'status': ca.status_types, 'time': ca.time_types, 'control': ca.control_types, 'native': ca.native_types } mod = next(k for k, v in mod_map.items() if xtype in v) nt_type = ca.native_type(xtype) fmt = '%i' if nt_type in (ca.ChType.FLOAT, ca.ChType.DOUBLE): fmt = '%g' elif nt_type in (ca.ChType.CHAR, ca.ChType.STRING): fmt = '%s' # self._set_charval(self._args['value'], call_ca=False) out.append("== %s (%s) ==" % (self.pvname, ca.DBR_TYPES[xtype].__name__)) if self.count == 1: val = self._args['value'] out.append(' value = %s' % fmt % val) else: ext = {True: '...', False: ''}[self.count > 10] elems = range(min(5, self.count)) try: aval = [fmt % self._args['value'][i] for i in elems] except TypeError: aval = ('unknown', ) out.append(" value = array [%s%s]" % (",".join(aval), ext)) for nam in ('char_value', 'count', 'nelm', 'type', 'units', 'precision', 'host', 'access', 'status', 'severity', 'timestamp', 'posixseconds', 'nanoseconds', 'upper_ctrl_limit', 'lower_ctrl_limit', 'upper_disp_limit', 'lower_disp_limit', 'upper_alarm_limit', 'lower_alarm_limit', 'upper_warning_limit', 'lower_warning_limit'): if hasattr(self, nam): att = getattr(self, nam) if att is not None: if nam == 'timestamp': def fmt_time(tstamp=None): "simple formatter for time values" if tstamp is None: tstamp = time.time() tstamp, frac = divmod(tstamp, 1) return "%s.%5.5i" % (time.strftime( "%Y-%m-%d %H:%M:%S", time.localtime(tstamp)), round(1.e5 * frac)) att = "%.3f (%s)" % (att, fmt_time(att)) elif nam == 'char_value': att = "'%s'" % att if len(nam) < 12: out.append(' %.11s= %s' % (nam + ' ' * 12, str(att))) else: out.append(' %.20s= %s' % (nam + ' ' * 20, str(att))) if xtype == 'enum': # list enum strings out.append(' enum strings: ') for index, nam in enumerate(self.enum_strs): out.append(" %i = %s " % (index, nam)) if len(self.chid.channel.subscriptions) > 0: msg = 'PV is internally monitored' out.append(' %s, with %i user-defined callbacks:' % (msg, len(self.callbacks))) if len(self.callbacks) > 0: for nam in sorted(self.callbacks.keys()): cback = self.callbacks[nam][0] out.append(' {!r}'.format(cback)) else: out.append(' PV is NOT internally monitored') out.append('=============================') return '\n'.join(out)
async def run_client_test(): print('* client_test', pv, dbr_type) db_entry = caget_pvdb[pv] # native type as in the ChannelData database db_native = ca.native_type(db_entry.data_type) # native type of the request req_native = ca.native_type(dbr_type) data = await run_caget(pv, dbr_type=dbr_type) print('dbr_type', dbr_type, 'data:') print(data) db_value = db_entry.value # convert from string value to enum if requesting int if (db_native == ChType.ENUM and not (req_native == ChType.STRING or dbr_type in (ChType.CTRL_ENUM, ChType.GR_ENUM))): db_value = db_entry.enum_strings.index(db_value) if req_native in (ChType.INT, ChType.LONG, ChType.SHORT, ChType.CHAR): if db_native == ChType.CHAR: assert int(data['value']) == ord(db_value) else: assert int(data['value']) == int(db_value) elif req_native in (ChType.STSACK_STRING, ): db_string_value = db_entry.alarm.alarm_string string_length = len(db_string_value) read_value = data['value'][:string_length] assert read_value == db_string_value elif req_native in (ChType.CLASS_NAME, ): assert data['class_name'] == 'caproto' elif req_native in (ChType.FLOAT, ChType.DOUBLE): assert float(data['value']) == float(db_value) elif req_native == ChType.STRING: if db_native == ChType.STRING: db_string_value = str(db_value) string_length = len(db_string_value) read_value = data['value'][:string_length] assert int(data['element_count']) == string_length assert read_value == db_string_value # due to how we monitor the caget output, we get @@@s where # null padding bytes are. so long as we verify element_count # above and the set of chars that should match, this assertion # should pass else: assert data['value'] == str(db_value) elif req_native == ChType.ENUM: bad_strings = ['Illegal Value (', 'Enum Index Overflow ('] for bad_string in bad_strings: if data['value'].startswith(bad_string): data['value'] = data['value'][len(bad_string):-1] if (db_native == ChType.ENUM and (dbr_type in (ChType.CTRL_ENUM, ChType.GR_ENUM))): # ctrl enum gets back the full string value assert data['value'] == db_value else: assert int(data['value']) == int(db_value) else: raise ValueError('TODO ' + str(dbr_type)) # TODO metadata should be cast to requested type as well! same_type = (ca.native_type(dbr_type) == db_native) if (dbr_type in ca.control_types and same_type and dbr_type != ChType.CTRL_ENUM): for key in ctrl_keys: if (key == 'precision' and ca.native_type(dbr_type) != ChType.DOUBLE): print('skipping', key) continue print('checking', key) assert float(data[key]) == getattr(db_entry, key), key if dbr_type in ca.time_types: timestamp = datetime.datetime.fromtimestamp(db_entry.timestamp) assert data['timestamp'] == timestamp if (dbr_type in ca.time_types or dbr_type in ca.status_types or dbr_type == ChType.STSACK_STRING): severity = data['severity'] if not severity.endswith('_ALARM'): severity = '{}_ALARM'.format(severity) severity = getattr(ca._dbr.AlarmSeverity, severity) assert severity == db_entry.severity, key status = data['status'] status = getattr(ca._dbr.AlarmStatus, status) assert status == db_entry.status, key if 'ackt' in data: ack_transient = data['ackt'] == 'YES' assert ack_transient == db_entry.alarm.acknowledge_transient if 'acks' in data: ack_severity = data['acks'] ack_severity = getattr(ca._dbr.AlarmSeverity, ack_severity) assert ack_severity == db_entry.alarm.acknowledge_severity