import os
+class _ConfigErrorCtx:
+ def __init__(self, name, msg=None):
+ self._name = name
+ self._msg = msg
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def msg(self):
+ return self._msg
+
+
class ConfigError(RuntimeError):
- def __init__(self, msg, prev=None):
- super().__init__(msg)
- self._prev = prev
+ def __init__(self, init_ctx_name, init_ctx_msg=None):
+ self._ctx = []
+ self.append_ctx(init_ctx_name, init_ctx_msg)
@property
- def prev(self):
- return self._prev
+ def ctx(self):
+ return self._ctx
+
+ def append_ctx(self, name, msg=None):
+ self._ctx.append(_ConfigErrorCtx(name, msg))
class Config:
validator.validate(meta)
validator = _MetadataSpecialFieldsValidator()
validator.validate(meta)
- except Exception as e:
- raise ConfigError('metadata error', e)
+ except ConfigError as exc:
+ exc.append_ctx('metadata')
+ raise
try:
validator = _BarectfMetadataValidator()
validator.validate(meta)
- except Exception as e:
- raise ConfigError('barectf metadata error', e)
+ except ConfigError as exc:
+ exc.append_ctx('barectf metadata')
+ raise
def _augment_metadata_env(self, meta):
version_tuple = barectf.get_version_tuple()
@prefix.setter
def prefix(self, value):
if not _is_valid_identifier(value):
- raise ConfigError('configuration prefix must be a valid C identifier')
+ raise ConfigError('configuration',
+ 'prefix must be a valid C identifier')
self._prefix = value
def _validate_int_type(self, t, entity_root):
if t.size > 64:
- raise ConfigError('integer type\'s size must be lesser than or equal to 64 bits')
+ raise ConfigError('integer type', 'size must be lesser than or equal to 64 bits')
def _validate_float_type(self, t, entity_root):
if t.size > 64:
- raise ConfigError('floating point number type\'s size must be lesser than or equal to 64 bits')
+ raise ConfigError('floating point number type', 'size must be lesser than or equal to 64 bits')
def _validate_enum_type(self, t, entity_root):
if t.value_type.size > 64:
- raise ConfigError('enumeration type\'s integer type\'s size must be lesser than or equal to 64 bits')
+ raise ConfigError('enumeration type', 'integer type\'s size must be lesser than or equal to 64 bits')
def _validate_string_type(self, t, entity_root):
pass
def _validate_struct_type(self, t, entity_root):
if not entity_root:
- raise ConfigError('inner structure types are not supported as of this version')
+ raise ConfigError('structure type', 'inner structure types are not supported as of this version')
for field_name, field_type in t.fields.items():
if entity_root and self._cur_entity is _Entity.TRACE_PACKET_HEADER:
try:
self._validate_type(field_type, False)
- except Exception as e:
- raise ConfigError('in structure type\'s field "{}"'.format(field_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('structure type\' field "{}"'.format(field_name))
+ raise
def _validate_array_type(self, t, entity_root):
- raise ConfigError('array types are not supported as of this version')
+ raise ConfigError('array type', 'not supported as of this version')
def _validate_type(self, t, entity_root):
self._type_to_validate_type_func[type(t)](t, entity_root)
# make sure entity is byte-aligned
if t.align < 8:
- raise ConfigError('type\'s alignment must be at least byte-aligned')
+ raise ConfigError('root type', 'alignment must be at least byte-aligned')
# make sure entity is a structure
if type(t) is not metadata.Struct:
- raise ConfigError('expecting a structure type')
+ raise ConfigError('root type', 'expecting a structure type')
# validate types
self._validate_type(t, True)
try:
self._validate_entity(meta.trace.packet_header_type)
- except Exception as e:
- raise ConfigError('invalid trace packet header type', e)
+ except ConfigError as exc:
+ exc.append_ctx('trace', 'invalid packet header type')
+ raise
for stream_name, stream in meta.streams.items():
if not _is_valid_identifier(stream_name):
- raise ConfigError('stream name "{}" is not a valid C identifier'.format(stream_name))
+ raise ConfigError('trace', 'stream name "{}" is not a valid C identifier'.format(stream_name))
self._cur_entity = _Entity.STREAM_PACKET_CONTEXT
try:
self._validate_entity(stream.packet_context_type)
- except Exception as e:
- raise ConfigError('invalid packet context type in stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name),
+ 'invalid packet context type')
+ raise
self._cur_entity = _Entity.STREAM_EVENT_HEADER
try:
self._validate_entity(stream.event_header_type)
- except Exception as e:
- raise ConfigError('invalid event header type in stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name),
+ 'invalid event header type')
+ raise
self._cur_entity = _Entity.STREAM_EVENT_CONTEXT
try:
self._validate_entity(stream.event_context_type)
- except Exception as e:
- raise ConfigError('invalid event context type in stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name),
+ 'invalid event context type'.format(stream_name))
+ raise
try:
for ev_name, ev in stream.events.items():
if not _is_valid_identifier(ev_name):
- raise ConfigError('event name "{}" is not a valid C identifier'.format(ev_name))
+ raise ConfigError('stream "{}"'.format(stream_name),
+ 'event name "{}" is not a valid C identifier'.format(ev_name))
self._cur_entity = _Entity.EVENT_CONTEXT
try:
self._validate_entity(ev.context_type)
- except Exception as e:
- raise ConfigError('invalid context type in event "{}"'.format(ev_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('event "{}"'.format(ev_name),
+ 'invalid context type')
+ raise
self._cur_entity = _Entity.EVENT_PAYLOAD
try:
self._validate_entity(ev.payload_type)
- except Exception as e:
- raise ConfigError('invalid payload type in event "{}"'.format(ev_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('event "{}"'.format(ev_name),
+ 'invalid payload type')
+ raise
if stream.is_event_empty(ev):
- raise ConfigError('event "{}" is empty'.format(ev_name))
- except Exception as e:
- raise ConfigError('invalid stream "{}"'.format(stream_name), e)
+ raise ConfigError('event "{}"'.format(ev_name), 'empty')
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name))
+ raise
def _validate_default_stream(self, meta):
if meta.default_stream_name:
if meta.default_stream_name not in meta.streams.keys():
- raise ConfigError('default stream name ("{}") does not exist'.format(meta.default_stream_name))
+ raise ConfigError('barectf metadata', 'default stream name ("{}") does not exist'.format(meta.default_stream_name))
def validate(self, meta):
self._validate_entities_and_names(meta)
if len(self._meta.streams) > 1:
# yes
if t is None:
- raise ConfigError('need "stream_id" field in trace packet header type (more than one stream), but trace packet header type is missing')
+ raise ConfigError('"packet-header-type" property',
+ 'need "stream_id" field (more than one stream), but trace packet header type is missing')
if type(t) is not metadata.Struct:
- raise ConfigError('need "stream_id" field in trace packet header type (more than one stream), but trace packet header type is not a structure type')
+ raise ConfigError('"packet-header-type" property',
+ 'need "stream_id" field (more than one stream), but trace packet header type is not a structure type')
if 'stream_id' not in t.fields:
- raise ConfigError('need "stream_id" field in trace packet header type (more than one stream)')
+ raise ConfigError('"packet-header-type" property',
+ 'need "stream_id" field (more than one stream)')
# validate "magic" and "stream_id" types
if type(t) is not metadata.Struct:
for i, (field_name, field_type) in enumerate(t.fields.items()):
if field_name == 'magic':
if type(field_type) is not metadata.Integer:
- raise ConfigError('"magic" field in trace packet header type must be an integer type')
+ raise ConfigError('"packet-header-type" property',
+ '"magic" field must be an integer type')
if field_type.signed or field_type.size != 32:
- raise ConfigError('"magic" field in trace packet header type must be a 32-bit unsigned integer type')
+ raise ConfigError('"packet-header-type" property',
+ '"magic" field must be a 32-bit unsigned integer type')
if i != 0:
- raise ConfigError('"magic" field must be the first trace packet header type\'s field')
+ raise ConfigError('"packet-header-type" property',
+ '"magic" field must be the first trace packet header type\'s field')
elif field_name == 'stream_id':
if type(field_type) is not metadata.Integer:
- raise ConfigError('"stream_id" field in trace packet header type must be an integer type')
+ raise ConfigError('"packet-header-type" property',
+ '"stream_id" field must be an integer type')
if field_type.signed:
- raise ConfigError('"stream_id" field in trace packet header type must be an unsigned integer type')
+ raise ConfigError('"packet-header-type" property',
+ '"stream_id" field must be an unsigned integer type')
# "id" size can fit all event IDs
if len(self._meta.streams) > (1 << field_type.size):
- raise ConfigError('"stream_id" field\' size in trace packet header type is too small for the number of trace streams')
+ raise ConfigError('"packet-header-type" property',
+ '"stream_id" field\' size is too small for the number of trace streams')
elif field_name == 'uuid':
if self._meta.trace.uuid is None:
- raise ConfigError('"uuid" field in trace packet header type specified, but no trace UUID provided')
+ raise ConfigError('"packet-header-type" property',
+ '"uuid" field specified, but no trace UUID provided')
if type(field_type) is not metadata.Array:
- raise ConfigError('"uuid" field in trace packet header type must be an array')
+ raise ConfigError('"packet-header-type" property',
+ '"uuid" field must be an array')
if field_type.length != 16:
- raise ConfigError('"uuid" field in trace packet header type must be an array of 16 bytes')
+ raise ConfigError('"packet-header-type" property',
+ '"uuid" field must be an array of 16 bytes')
element_type = field_type.element_type
if type(element_type) is not metadata.Integer:
- raise ConfigError('"uuid" field in trace packet header type must be an array of 16 unsigned bytes')
+ raise ConfigError('"packet-header-type" property',
+ '"uuid" field must be an array of 16 unsigned bytes')
if element_type.size != 8:
- raise ConfigError('"uuid" field in trace packet header type must be an array of 16 unsigned bytes')
+ raise ConfigError('"packet-header-type" property',
+ '"uuid" field must be an array of 16 unsigned bytes')
if element_type.signed:
- raise ConfigError('"uuid" field in trace packet header type must be an array of 16 unsigned bytes')
+ raise ConfigError('"packet-header-type" property',
+ '"uuid" field must be an array of 16 unsigned bytes')
if element_type.align != 8:
- raise ConfigError('"uuid" field in trace packet header type must be an array of 16 unsigned, byte-aligned bytes')
+ raise ConfigError('"packet-header-type" property',
+ '"uuid" field must be an array of 16 unsigned, byte-aligned bytes')
def _validate_trace(self, meta):
self._validate_trace_packet_header_type(meta.trace.packet_header_type)
t = stream.packet_context_type
if type(t) is None:
- raise ConfigError('missing "packet-context-type" property in stream object')
+ raise ConfigError('stream',
+ 'missing "packet-context-type" property')
if type(t) is not metadata.Struct:
- raise ConfigError('"packet-context-type": expecting a structure type')
+ raise ConfigError('"packet-context-type" property',
+ 'expecting a structure type')
# "timestamp_begin", if exists, is an unsigned integer type,
# mapped to a clock
ts_begin = t.fields['timestamp_begin']
if type(ts_begin) is not metadata.Integer:
- raise ConfigError('"timestamp_begin" field in stream packet context type must be an integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"timestamp_begin" field must be an integer type')
if ts_begin.signed:
- raise ConfigError('"timestamp_begin" field in stream packet context type must be an unsigned integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"timestamp_begin" field must be an unsigned integer type')
if not ts_begin.property_mappings:
- raise ConfigError('"timestamp_begin" field in stream packet context type must be mapped to a clock')
+ raise ConfigError('"packet-context-type" property',
+ '"timestamp_begin" field must be mapped to a clock')
# "timestamp_end", if exists, is an unsigned integer type,
# mapped to a clock
ts_end = t.fields['timestamp_end']
if type(ts_end) is not metadata.Integer:
- raise ConfigError('"timestamp_end" field in stream packet context type must be an integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"timestamp_end" field must be an integer type')
if ts_end.signed:
- raise ConfigError('"timestamp_end" field in stream packet context type must be an unsigned integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"timestamp_end" field must be an unsigned integer type')
if not ts_end.property_mappings:
- raise ConfigError('"timestamp_end" field in stream packet context type must be mapped to a clock')
+ raise ConfigError('"packet-context-type" property',
+ '"timestamp_end" field must be mapped to a clock')
# "timestamp_begin" and "timestamp_end" exist together
if (('timestamp_begin' in t.fields) ^ ('timestamp_end' in t.fields)):
events_discarded = t.fields['events_discarded']
if type(events_discarded) is not metadata.Integer:
- raise ConfigError('"events_discarded" field in stream packet context type must be an integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"events_discarded" field must be an integer type')
if events_discarded.signed:
- raise ConfigError('"events_discarded" field in stream packet context type must be an unsigned integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"events_discarded" field must be an unsigned integer type')
# "packet_size" and "content_size" must exist
if 'packet_size' not in t.fields:
- raise ConfigError('missing "packet_size" field in stream packet context type')
+ raise ConfigError('"packet-context-type" property',
+ 'missing "packet_size" field in stream packet context type')
packet_size = t.fields['packet_size']
# "content_size" and "content_size" must exist
if 'content_size' not in t.fields:
- raise ConfigError('missing "content_size" field in stream packet context type')
+ raise ConfigError('"packet-context-type" property',
+ 'missing "content_size" field in stream packet context type')
content_size = t.fields['content_size']
# "packet_size" is an unsigned integer type
if type(packet_size) is not metadata.Integer:
- raise ConfigError('"packet_size" field in stream packet context type must be an integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"packet_size" field in stream packet context type must be an integer type')
if packet_size.signed:
- raise ConfigError('"packet_size" field in stream packet context type must be an unsigned integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"packet_size" field in stream packet context type must be an unsigned integer type')
# "content_size" is an unsigned integer type
if type(content_size) is not metadata.Integer:
- raise ConfigError('"content_size" field in stream packet context type must be an integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"content_size" field in stream packet context type must be an integer type')
if content_size.signed:
- raise ConfigError('"content_size" field in stream packet context type must be an unsigned integer type')
+ raise ConfigError('"packet-context-type" property',
+ '"content_size" field in stream packet context type must be an unsigned integer type')
# "packet_size" size should be greater than or equal to "content_size" size
if content_size.size > packet_size.size:
- raise ConfigError('"content_size" field size must be lesser than or equal to "packet_size" field size')
+ raise ConfigError('"packet-context-type" property',
+ '"content_size" field size must be lesser than or equal to "packet_size" field size')
def _validate_stream_event_header(self, stream):
t = stream.event_header_type
if len(stream.events) > 1:
# yes
if t is None:
- raise ConfigError('need "id" field in stream event header type (more than one event), but stream event header type is missing')
+ raise ConfigError('"event-header-type" property',
+ 'need "id" field (more than one event), but stream event header type is missing')
if type(t) is not metadata.Struct:
- raise ConfigError('need "id" field in stream event header type (more than one event), but stream event header type is not a structure type')
+ raise ConfigError('"event-header-type" property',
+ 'need "id" field (more than one event), but stream event header type is not a structure type')
if 'id' not in t.fields:
- raise ConfigError('need "id" field in stream event header type (more than one event)')
+ raise ConfigError('"event-header-type" property',
+ 'need "id" field (more than one event)')
# validate "id" and "timestamp" types
if type(t) is not metadata.Struct:
ts = t.fields['timestamp']
if type(ts) is not metadata.Integer:
- raise ConfigError('"timestamp" field in stream event header type must be an integer type')
+ raise ConfigError('"event-header-type" property',
+ '"timestamp" field must be an integer type')
if ts.signed:
- raise ConfigError('"timestamp" field in stream event header type must be an unsigned integer type')
+ raise ConfigError('"event-header-type" property',
+ '"timestamp" field must be an unsigned integer type')
if not ts.property_mappings:
- raise ConfigError('"timestamp" field in stream event header type must be mapped to a clock')
+ raise ConfigError('"event-header-type" property',
+ '"timestamp" field must be mapped to a clock')
if 'id' in t.fields:
eid = t.fields['id']
# "id" is an unsigned integer type
if type(eid) is not metadata.Integer:
- raise ConfigError('"id" field in stream event header type must be an integer type')
+ raise ConfigError('"event-header-type" property',
+ '"id" field must be an integer type')
if eid.signed:
- raise ConfigError('"id" field in stream event header type must be an unsigned integer type')
+ raise ConfigError('"event-header-type" property',
+ '"id" field must be an unsigned integer type')
# "id" size can fit all event IDs
if len(stream.events) > (1 << eid.size):
- raise ConfigError('"id" field\' size in stream event header type is too small for the number of stream events')
+ raise ConfigError('"event-header-type" property',
+ '"id" field\' size is too small for the number of stream events')
def _validate_stream(self, stream):
self._validate_stream_packet_context(stream)
for stream in meta.streams.values():
try:
self._validate_stream(stream)
- except Exception as e:
- raise ConfigError('invalid stream "{}"'.format(stream.name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream.name), 'invalid')
+ raise
# Entities. Order of values is important here.
def _validate_integer_histology(self, t):
# size is set
if t.size is None:
- raise ConfigError('missing integer type\'s size')
+ raise ConfigError('integer type', 'missing size')
def _validate_float_histology(self, t):
# exponent digits is set
if t.exp_size is None:
- raise ConfigError('missing floating point number type\'s exponent size')
+ raise ConfigError('floating point number type',
+ 'missing exponent size')
# mantissa digits is set
if t.mant_size is None:
- raise ConfigError('missing floating point number type\'s mantissa size')
+ raise ConfigError('floating point number type',
+ 'missing mantissa size')
# exponent and mantissa sum is a multiple of 8
if (t.exp_size + t.mant_size) % 8 != 0:
- raise ConfigError('floating point number type\'s mantissa and exponent sizes sum must be a multiple of 8')
+ raise ConfigError('floating point number type',
+ 'mantissa and exponent sizes sum must be a multiple of 8')
def _validate_enum_histology(self, t):
# integer type is set
if t.value_type is None:
- raise ConfigError('missing enumeration type\'s value type')
+ raise ConfigError('enumeration type', 'missing value type')
# there's at least one member
if not t.members:
- raise ConfigError('enumeration type needs at least one member')
+ raise ConfigError('enumeration type', 'at least one member required')
# no overlapping values and all values are valid considering
# the value type
for label, value in t.members.items():
for rg in ranges:
if value[0] <= rg[1] and rg[0] <= value[1]:
- raise ConfigError('enumeration type\'s member "{}" overlaps another member'.format(label))
+ raise ConfigError('enumeration type\'s member "{}"',
+ 'overlaps another member'.format(label))
- fmt = 'enumeration type\'s member "{}": value {} is outside the value type range [{}, {}]'
+ name_fmt = 'enumeration type\'s member "{}"'
+ msg_fmt = 'value {} is outside the value type range [{}, {}]'
if value[0] < value_min or value[0] > value_max:
- raise ConfigError(fmt.format(label, value[0], value_min, value_max))
+ raise ConfigError(name_fmt.format(label),
+ msg_fmt.format(value[0], value_min, value_max))
if value[1] < value_min or value[1] > value_max:
- raise ConfigError(fmt.format(label, value[1], value_min, value_max))
+ raise ConfigError(name_fmt.format(label),
+ msg_fmt.format(value[0], value_min, value_max))
ranges.append(value)
for field_name, field_type in t.fields.items():
try:
self._validate_type_histology(field_type)
- except Exception as e:
- raise ConfigError('invalid structure type\'s field "{}"'.format(field_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('structure type\'s field "{}"'.format(field_name))
+ raise
def _validate_array_histology(self, t):
# length is set
if t.length is None:
- raise ConfigError('missing array type\'s length')
+ raise ConfigError('array type', 'missing length')
# element type is set
if t.element_type is None:
- raise ConfigError('missing array type\'s element type')
+ raise ConfigError('array type', 'missing element type')
# element type is valid
try:
self._validate_type_histology(t.element_type)
- except Exception as e:
- raise ConfigError('invalid array type\'s element type', e)
+ except ConfigError as exc:
+ exc.append_ctx('array type', 'invalid element type')
+ raise
def _validate_type_histology(self, t):
if t is None:
return
if type(t) is not metadata.Struct:
- raise ConfigError('expecting a structure type')
+ raise ConfigError('root type', 'expecting a structure type')
self._validate_type_histology(t)
# validate event context type
try:
self._validate_entity_type_histology(ev.context_type)
- except Exception as e:
- raise ConfigError('invalid event context type for event "{}"'.format(ev_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('event "{}"'.format(ev.name),
+ 'invalid context type')
+ raise
# validate event payload type
try:
self._validate_entity_type_histology(ev.payload_type)
- except Exception as e:
- raise ConfigError('invalid event payload type for event "{}"'.format(ev_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('event "{}"'.format(ev.name),
+ 'invalid payload type')
+ raise
def _validate_stream_types_histology(self, stream):
stream_name = stream.name
# validate stream packet context type
try:
self._validate_entity_type_histology(stream.packet_context_type)
- except Exception as e:
- raise ConfigError('invalid stream packet context type for stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name),
+ 'invalid packet context type')
+ raise
# validate stream event header type
try:
self._validate_entity_type_histology(stream.event_header_type)
- except Exception as e:
- raise ConfigError('invalid stream event header type for stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name),
+ 'invalid event header type')
+ raise
# validate stream event context type
try:
self._validate_entity_type_histology(stream.event_context_type)
- except Exception as e:
- raise ConfigError('invalid stream event context type for stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name),
+ 'invalid event context type')
+ raise
# validate events
for ev in stream.events.values():
try:
self._validate_event_types_histology(ev)
- except Exception as e:
- raise ConfigError('invalid event in stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream "{}"'.format(stream_name),
+ 'invalid event')
+ raise
def validate(self, meta):
# validate trace packet header type
try:
self._validate_entity_type_histology(meta.trace.packet_header_type)
- except Exception as e:
- raise ConfigError('invalid trace packet header type', e)
+ except ConfigError as exc:
+ exc.append_ctx('metadata\'s trace', 'invalid packet header type')
+ raise
# validate streams
for stream in meta.streams.values():
def _set_byte_order(self, metadata_node):
if 'trace' not in metadata_node:
- raise ConfigError('missing "trace" property (metadata)')
+ raise ConfigError('metadata', 'missing "trace" property')
trace_node = metadata_node['trace']
if not _is_assoc_array_prop(trace_node):
- raise ConfigError('"trace" property (metadata) must be an associative array')
+ raise ConfigError('metadata\'s "trace" property',
+ 'must be an associative array')
if 'byte-order' not in trace_node:
- raise ConfigError('missing "byte-order" property (trace)')
+ raise ConfigError('metadata\'s "trace" property',
+ 'missing "byte-order" property')
bo_node = trace_node['byte-order']
if not _is_str_prop(bo_node):
- raise ConfigError('"byte-order" property of trace object must be a string ("le" or "be")')
+ raise ConfigError('metadata\'s "trace" property',
+ '"byte-order" property must be a string ("le" or "be")')
self._bo = _byte_order_str_to_bo(bo_node)
if self._bo is None:
- raise ConfigError('invalid "byte-order" property (trace): must be "le" or "be"')
+ raise ConfigError('metadata\'s "trace" property',
+ 'invalid "byte-order" property: must be "le" or "be"')
def _lookup_type_alias(self, name):
if name in self._tas:
unk_prop = _get_first_unknown_prop(prop_mapping_node, ['type', 'name', 'property'])
if unk_prop:
- raise ConfigError('unknown property in integer type object\'s clock property mapping: "{}"'.format(unk_prop))
+ raise ConfigError('integer type\'s clock property mapping',
+ 'unknown property: "{}"'.format(unk_prop))
if 'name' not in prop_mapping_node:
- raise ConfigError('missing "name" property in integer type object\'s clock property mapping')
+ raise ConfigError('integer type\'s clock property mapping',
+ 'missing "name" property')
if 'property' not in prop_mapping_node:
- raise ConfigError('missing "property" property in integer type object\'s clock property mapping')
+ raise ConfigError('integer type\'s clock property mapping',
+ 'missing "property" property')
clock_name = prop_mapping_node['name']
prop = prop_mapping_node['property']
if not _is_str_prop(clock_name):
- raise ConfigError('"name" property of integer type object\'s clock property mapping must be a string')
+ raise ConfigError('integer type\'s clock property mapping',
+ '"name" property must be a string')
if not _is_str_prop(prop):
- raise ConfigError('"property" property of integer type object\'s clock property mapping must be a string')
+ raise ConfigError('integer type\'s clock property mapping',
+ '"property" property must be a string')
if clock_name not in self._clocks:
- raise ConfigError('invalid clock name "{}" in integer type object\'s clock property mapping'.format(clock_name))
+ raise ConfigError('integer type\'s clock property mapping',
+ 'invalid clock name "{}"'.format(clock_name))
if prop != 'value':
- raise ConfigError('invalid "property" property in integer type object\'s clock property mapping: "{}"'.format(prop))
+ raise ConfigError('integer type\'s clock property mapping',
+ 'invalid "property" property: "{}"'.format(prop))
mapped_clock = self._clocks[clock_name]
int_obj.property_mappings.append(metadata.PropertyMapping(mapped_clock, prop))
])
if unk_prop:
- raise ConfigError('unknown integer type object property: "{}"'.format(unk_prop))
+ raise ConfigError('integer type',
+ 'unknown property: "{}"'.format(unk_prop))
# size
if 'size' in node:
size = node['size']
if not _is_int_prop(size):
- raise ConfigError('"size" property of integer type object must be an integer')
+ raise ConfigError('integer type',
+ '"size" property of integer type object must be an integer')
if size < 1:
- raise ConfigError('invalid integer size: {}'.format(size))
+ raise ConfigError('integer type',
+ 'invalid integer size: {}'.format(size))
obj.size = size
obj.set_default_align()
else:
if not _is_int_prop(align):
- raise ConfigError('"align" property of integer type object must be an integer')
+ raise ConfigError('integer type',
+ '"align" property of integer type object must be an integer')
if not _is_valid_alignment(align):
- raise ConfigError('invalid alignment: {}'.format(align))
+ raise ConfigError('integer type',
+ 'invalid alignment: {}'.format(align))
obj.align = align
obj.set_default_signed()
else:
if not _is_bool_prop(signed):
- raise ConfigError('"signed" property of integer type object must be a boolean')
+ raise ConfigError('integer type',
+ '"signed" property of integer type object must be a boolean')
obj.signed = signed
obj.byte_order = self._bo
else:
if not _is_str_prop(byte_order):
- raise ConfigError('"byte-order" property of integer type object must be a string ("le" or "be")')
+ raise ConfigError('integer type',
+ '"byte-order" property of integer type object must be a string ("le" or "be")')
byte_order = _byte_order_str_to_bo(byte_order)
if byte_order is None:
- raise ConfigError('invalid "byte-order" property in integer type object')
+ raise ConfigError('integer type',
+ 'invalid "byte-order" property in integer type object')
obj.byte_order = byte_order
else:
obj.set_default_base()
else:
if not _is_str_prop(base):
- raise ConfigError('"base" property of integer type object must be a string ("bin", "oct", "dec", or "hex")')
+ raise ConfigError('integer type',
+ '"base" property of integer type object must be a string ("bin", "oct", "dec", or "hex")')
if base == 'bin':
base = 2
elif base == 'hex':
base = 16
else:
- raise ConfigError('unknown "base" property value: "{}" ("bin", "oct", "dec", and "hex" are accepted)'.format(base))
+ raise ConfigError('integer type',
+ 'unknown "base" property value: "{}" ("bin", "oct", "dec", and "hex" are accepted)'.format(base))
obj.base = base
obj.set_default_encoding()
else:
if not _is_str_prop(encoding):
- raise ConfigError('"encoding" property of integer type object must be a string ("none", "ascii", or "utf-8")')
+ raise ConfigError('integer type',
+ '"encoding" property of integer type object must be a string ("none", "ascii", or "utf-8")')
encoding = _encoding_str_to_encoding(encoding)
if encoding is None:
- raise ConfigError('invalid "encoding" property in integer type object')
+ raise ConfigError('integer type',
+ 'invalid "encoding" property in integer type object')
obj.encoding = encoding
obj.set_default_property_mappings()
else:
if not _is_array_prop(prop_mappings):
- raise ConfigError('"property-mappings" property of integer type object must be an array')
+ raise ConfigError('integer type',
+ '"property-mappings" property of integer type object must be an array')
if len(prop_mappings) > 1:
- raise ConfigError('length of "property-mappings" array in integer type object must be 1')
+ raise ConfigError('integer type',
+ 'length of "property-mappings" array in integer type object must be 1')
for index, prop_mapping in enumerate(prop_mappings):
if not _is_assoc_array_prop(prop_mapping):
- raise ConfigError('elements of "property-mappings" property of integer type object must be associative arrays')
+ raise ConfigError('integer type',
+ 'elements of "property-mappings" property of integer type object must be associative arrays')
if 'type' not in prop_mapping:
- raise ConfigError('missing "type" property in integer type object\'s "property-mappings" array\'s element #{}'.format(index))
+ raise ConfigError('integer type',
+ 'missing "type" property in integer type object\'s "property-mappings" array\'s element #{}'.format(index))
prop_type = prop_mapping['type']
if not _is_str_prop(prop_type):
- raise ConfigError('"type" property of integer type object\'s "property-mappings" array\'s element #{} must be a string'.format(index))
+ raise ConfigError('integer type',
+ '"type" property of integer type object\'s "property-mappings" array\'s element #{} must be a string'.format(index))
if prop_type == 'clock':
self._set_int_clock_prop_mapping(obj, prop_mapping)
else:
- raise ConfigError('unknown property mapping type "{}" in integer type object\'s "property-mappings" array\'s element #{}'.format(prop_type, index))
+ raise ConfigError('integer type',
+ 'unknown property mapping type "{}" in integer type object\'s "property-mappings" array\'s element #{}'.format(prop_type, index))
return obj
])
if unk_prop:
- raise ConfigError('unknown floating point number type object property: "{}"'.format(unk_prop))
+ raise ConfigError('floating point number type',
+ 'unknown property: "{}"'.format(unk_prop))
# size
if 'size' in node:
size = node['size']
if not _is_assoc_array_prop(size):
- raise ConfigError('"size" property of floating point number type object must be an associative array')
+ raise ConfigError('floating point number type',
+ '"size" property must be an associative array')
unk_prop = _get_first_unknown_prop(size, ['exp', 'mant'])
if unk_prop:
- raise ConfigError('unknown floating point number type object\'s "size" property: "{}"'.format(unk_prop))
+ raise ConfigError('floating point number type\'s "size" property',
+ 'unknown property: "{}"'.format(unk_prop))
if 'exp' in size:
exp = size['exp']
if not _is_int_prop(exp):
- raise ConfigError('"exp" property of floating point number type object\'s "size" property must be an integer')
+ raise ConfigError('floating point number type\'s "size" property',
+ '"exp" property must be an integer')
if exp < 1:
- raise ConfigError('invalid floating point number exponent size: {}')
+ raise ConfigError('floating point number type\'s "size" property',
+ 'invalid exponent size: {}')
obj.exp_size = exp
mant = size['mant']
if not _is_int_prop(mant):
- raise ConfigError('"mant" property of floating point number type object\'s "size" property must be an integer')
+ raise ConfigError('floating point number type\'s "size" property',
+ '"mant" property must be an integer')
if mant < 1:
- raise ConfigError('invalid floating point number mantissa size: {}')
+ raise ConfigError('floating point number type\'s "size" property',
+ 'invalid mantissa size: {}')
obj.mant_size = mant
obj.set_default_align()
else:
if not _is_int_prop(align):
- raise ConfigError('"align" property of floating point number type object must be an integer')
+ raise ConfigError('floating point number type',
+ '"align" property must be an integer')
if not _is_valid_alignment(align):
- raise ConfigError('invalid alignment: {}'.format(align))
+ raise ConfigError('floating point number type',
+ 'invalid alignment: {}'.format(align))
obj.align = align
obj.byte_order = self._bo
else:
if not _is_str_prop(byte_order):
- raise ConfigError('"byte-order" property of floating point number type object must be a string ("le" or "be")')
+ raise ConfigError('floating point number type',
+ '"byte-order" property must be a string ("le" or "be")')
byte_order = _byte_order_str_to_bo(byte_order)
if byte_order is None:
- raise ConfigError('invalid "byte-order" property in floating point number type object')
+ raise ConfigError('floating point number type',
+ 'invalid "byte-order" property')
else:
obj.byte_order = self._bo
])
if unk_prop:
- raise ConfigError('unknown enumeration type object property: "{}"'.format(unk_prop))
+ raise ConfigError('enumeration type',
+ 'unknown property: "{}"'.format(unk_prop))
# value type
if 'value-type' in node:
try:
obj.value_type = self._create_type(value_type_node)
- except Exception as e:
- raise ConfigError('cannot create enumeration type\'s integer type', e)
+ except ConfigError as exc:
+ exc.append_ctx('enumeration type', 'cannot create integer type')
+ raise
# members
if 'members' in node:
members_node = node['members']
if not _is_array_prop(members_node):
- raise ConfigError('"members" property of enumeration type object must be an array')
+ raise ConfigError('enumeration type',
+ '"members" property must be an array')
cur = 0
last_value = obj.last_value
for index, m_node in enumerate(members_node):
if not _is_str_prop(m_node) and not _is_assoc_array_prop(m_node):
- raise ConfigError('invalid enumeration member #{}: expecting a string or an associative array'.format(index))
+ raise ConfigError('enumeration type',
+ 'invalid member #{}: expecting a string or an associative array'.format(index))
if _is_str_prop(m_node):
label = m_node
])
if unk_prop:
- raise ConfigError('unknown enumeration type member object property: "{}"'.format(unk_prop))
+ raise ConfigError('enumeration type',
+ 'unknown member object property: "{}"'.format(unk_prop))
if 'label' not in m_node:
- raise ConfigError('missing "label" property in enumeration member #{}'.format(index))
+ raise ConfigError('enumeration type',
+ 'missing "label" property in member #{}'.format(index))
label = m_node['label']
if not _is_str_prop(label):
- raise ConfigError('"label" property of enumeration member #{} must be a string'.format(index))
+ raise ConfigError('enumeration type',
+ '"label" property of member #{} must be a string'.format(index))
if 'value' not in m_node:
- raise ConfigError('missing "value" property in enumeration member ("{}")'.format(label))
+ raise ConfigError('enumeration type',
+ 'missing "value" property in member ("{}")'.format(label))
value = m_node['value']
if not _is_int_prop(value) and not _is_array_prop(value):
- raise ConfigError('invalid enumeration member ("{}"): expecting an integer or an array'.format(label))
+ raise ConfigError('enumeration type',
+ 'invalid member ("{}"): expecting an integer or an array'.format(label))
if _is_int_prop(value):
cur = value + 1
value = (value, value)
else:
if len(value) != 2:
- raise ConfigError('invalid enumeration member ("{}"): range must have exactly two items'.format(label))
+ raise ConfigError('enumeration type',
+ 'invalid member ("{}"): range must have exactly two items'.format(label))
mn = value[0]
mx = value[1]
if mn > mx:
- raise ConfigError('invalid enumeration member ("{}"): invalid range ({} > {})'.format(label, mn, mx))
+ raise ConfigError('enumeration type',
+ 'invalid member ("{}"): invalid range ({} > {})'.format(label, mn, mx))
value = (mn, mx)
cur = mx + 1
])
if unk_prop:
- raise ConfigError('unknown string type object property: "{}"'.format(unk_prop))
+ raise ConfigError('string type',
+ 'unknown object property: "{}"'.format(unk_prop))
# encoding
if 'encoding' in node:
obj.set_default_encoding()
else:
if not _is_str_prop(encoding):
- raise ConfigError('"encoding" property of string type object must be a string ("none", "ascii", or "utf-8")')
+ raise ConfigError('string type',
+ '"encoding" property of must be a string ("none", "ascii", or "utf-8")')
encoding = _encoding_str_to_encoding(encoding)
if encoding is None:
- raise ConfigError('invalid "encoding" property in string type object')
+ raise ConfigError('string type',
+ 'invalid "encoding" property')
obj.encoding = encoding
])
if unk_prop:
- raise ConfigError('unknown string type object property: "{}"'.format(unk_prop))
+ raise ConfigError('structure type',
+ 'unknown object property: "{}"'.format(unk_prop))
# minimum alignment
if 'min-align' in node:
obj.set_default_min_align()
else:
if not _is_int_prop(min_align):
- raise ConfigError('"min-align" property of structure type object must be an integer')
+ raise ConfigError('structure type',
+ '"min-align" property must be an integer')
if not _is_valid_alignment(min_align):
- raise ConfigError('invalid minimum alignment: {}'.format(min_align))
+ raise ConfigError('structure type',
+ 'invalid minimum alignment: {}'.format(min_align))
obj.min_align = min_align
obj.set_default_fields()
else:
if not _is_assoc_array_prop(fields):
- raise ConfigError('"fields" property of structure type object must be an associative array')
+ raise ConfigError('structure type',
+ '"fields" property must be an associative array')
for field_name, field_node in fields.items():
if not _is_valid_identifier(field_name):
- raise ConfigError('"{}" is not a valid field name for structure type'.format(field_name))
+ raise ConfigError('structure type',
+ '"{}" is not a valid field name'.format(field_name))
try:
obj.fields[field_name] = self._create_type(field_node)
- except Exception as e:
- raise ConfigError('cannot create structure type\'s field "{}"'.format(field_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('structure type',
+ 'cannot create field "{}"'.format(field_name))
+ raise
return obj
])
if unk_prop:
- raise ConfigError('unknown array type object property: "{}"'.format(unk_prop))
+ raise ConfigError('array type',
+ 'unknown property: "{}"'.format(unk_prop))
# length
if 'length' in node:
length = node['length']
if not _is_int_prop(length):
- raise ConfigError('"length" property of array type object must be an integer')
+ raise ConfigError('array type',
+ '"length" property must be an integer')
if type(length) is int and length < 0:
- raise ConfigError('invalid static array length: {}'.format(length))
+ raise ConfigError('array type',
+ 'invalid length: {}'.format(length))
obj.length = length
try:
obj.element_type = self._create_type(node['element-type'])
- except Exception as e:
- raise ConfigError('cannot create array type\'s element type', e)
+ except ConfigError as exc:
+ exc.append_ctx('array type', 'cannot create element type')
+ raise
return obj
t = self._lookup_type_alias(type_node)
if t is None:
- raise ConfigError('unknown type alias "{}"'.format(type_node))
+ raise ConfigError('type',
+ 'unknown type alias "{}"'.format(type_node))
return t
if not _is_assoc_array_prop(type_node):
- raise ConfigError('type objects must be associative arrays or strings (type alias name)')
+ raise ConfigError('type',
+ 'expecting associative arrays or string (type alias name)')
# inherit:
# v2.0: "inherit"
if self._version >= 201:
if '$inherit' in type_node:
if inherit_node is not None:
- raise ConfigError('cannot specify both "inherit" and "$inherit" properties of type object: prefer "$inherit"')
+ raise ConfigError('type',
+ 'cannot specify both "inherit" and "$inherit" properties of type object: prefer "$inherit"')
inherit_prop = '$inherit'
inherit_node = type_node[inherit_prop]
if inherit_node is not None and 'class' in type_node:
- raise ConfigError('cannot specify both "{}" and "class" properties in type object'.format(inherit_prop))
+ raise ConfigError('type',
+ 'cannot specify both "{}" and "class" properties in type object'.format(inherit_prop))
if inherit_node is not None:
if not _is_str_prop(inherit_node):
- raise ConfigError('"{}" property of type object must be a string'.format(inherit_prop))
+ raise ConfigError('type',
+ '"{}" property of type object must be a string'.format(inherit_prop))
base = self._lookup_type_alias(inherit_node)
if base is None:
- raise ConfigError('cannot inherit from type alias "{}": type alias does not exist at this point'.format(inherit_node))
+ raise ConfigError('type',
+ 'cannot inherit from type alias "{}": type alias does not exist at this point'.format(inherit_node))
func = self._type_to_create_type_func[type(base)]
else:
if 'class' not in type_node:
- raise ConfigError('type objects which do not inherit must have a "class" property')
+ raise ConfigError('type',
+ 'does not inherit, therefore must have a "class" property')
class_name = type_node['class']
if type(class_name) is not str:
- raise ConfigError('type objects\' "class" property must be a string')
+ raise ConfigError('type', '"class" property must be a string')
if class_name not in self._class_name_to_create_type_func:
- raise ConfigError('unknown type class "{}"'.format(class_name))
+ raise ConfigError('type',
+ 'unknown class "{}"'.format(class_name))
base = None
func = self._class_name_to_create_type_func[class_name]
return
if not _is_assoc_array_prop(ta_node):
- raise ConfigError('"type-aliases" property (metadata) must be an associative array')
+ raise ConfigError('metadata',
+ '"type-aliases" property must be an associative array')
for ta_name, ta_type in ta_node.items():
if ta_name in self._tas:
- raise ConfigError('duplicate type alias "{}"'.format(ta_name))
+ raise ConfigError('metadata',
+ 'duplicate type alias "{}"'.format(ta_name))
try:
t = self._create_type(ta_type)
- except Exception as e:
- raise ConfigError('cannot create type alias "{}"'.format(ta_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('metadata',
+ 'cannot create type alias "{}"'.format(ta_name))
+ raise
self._tas[ta_name] = t
clock = metadata.Clock()
if not _is_assoc_array_prop(node):
- raise ConfigError('clock objects must be associative arrays')
+ raise ConfigError('metadata',
+ 'clock objects must be associative arrays')
known_props = [
'uuid',
unk_prop = _get_first_unknown_prop(node, known_props)
if unk_prop:
- raise ConfigError('unknown clock object property: "{}"'.format(unk_prop))
+ raise ConfigError('clock',
+ 'unknown property: "{}"'.format(unk_prop))
# UUID
if 'uuid' in node:
clock.set_default_uuid()
else:
if not _is_str_prop(uuidp):
- raise ConfigError('"uuid" property of clock object must be a string')
+ raise ConfigError('clock',
+ '"uuid" property must be a string')
try:
uuidp = uuid.UUID(uuidp)
except:
- raise ConfigError('malformed UUID (clock object): "{}"'.format(uuidp))
+ raise ConfigError('clock', 'malformed UUID: "{}"'.format(uuidp))
clock.uuid = uuidp
clock.set_default_description()
else:
if not _is_str_prop(desc):
- raise ConfigError('"description" property of clock object must be a string')
+ raise ConfigError('clock',
+ '"description" property must be a string')
clock.description = desc
clock.set_default_freq()
else:
if not _is_int_prop(freq):
- raise ConfigError('"freq" property of clock object must be an integer')
+ raise ConfigError('clock',
+ '"freq" property must be an integer')
if freq < 1:
- raise ConfigError('invalid clock frequency: {}'.format(freq))
+ raise ConfigError('clock',
+ 'invalid frequency: {}'.format(freq))
clock.freq = freq
clock.set_default_error_cycles()
else:
if not _is_int_prop(error_cycles):
- raise ConfigError('"error-cycles" property of clock object must be an integer')
+ raise ConfigError('clock',
+ '"error-cycles" property must be an integer')
if error_cycles < 0:
- raise ConfigError('invalid clock error cycles: {}'.format(error_cycles))
+ raise ConfigError('clock',
+ 'invalid error cycles: {}'.format(error_cycles))
clock.error_cycles = error_cycles
clock.set_default_offset_cycles()
else:
if not _is_assoc_array_prop(offset):
- raise ConfigError('"offset" property of clock object must be an associative array')
+ raise ConfigError('clock',
+ '"offset" property must be an associative array')
unk_prop = _get_first_unknown_prop(offset, ['cycles', 'seconds'])
if unk_prop:
- raise ConfigError('unknown clock object\'s offset property: "{}"'.format(unk_prop))
+ raise ConfigError('clock',
+ 'unknown offset property: "{}"'.format(unk_prop))
# cycles
if 'cycles' in offset:
clock.set_default_offset_cycles()
else:
if not _is_int_prop(offset_cycles):
- raise ConfigError('"cycles" property of clock object\'s offset property must be an integer')
+ raise ConfigError('clock\'s "offset" property',
+ '"cycles" property must be an integer')
if offset_cycles < 0:
- raise ConfigError('invalid clock offset cycles: {}'.format(offset_cycles))
+ raise ConfigError('clock\'s "offset" property',
+ 'invalid cycles: {}'.format(offset_cycles))
clock.offset_cycles = offset_cycles
clock.set_default_offset_seconds()
else:
if not _is_int_prop(offset_seconds):
- raise ConfigError('"seconds" property of clock object\'s offset property must be an integer')
+ raise ConfigError('clock\'s "offset" property',
+ '"seconds" property must be an integer')
if offset_seconds < 0:
- raise ConfigError('invalid clock offset seconds: {}'.format(offset_seconds))
+ raise ConfigError('clock\'s "offset" property',
+ 'invalid seconds: {}'.format(offset_seconds))
clock.offset_seconds = offset_seconds
clock.set_default_absolute()
else:
if not _is_bool_prop(absolute):
- raise ConfigError('"absolute" property of clock object must be a boolean')
+ raise ConfigError('clock',
+ '"absolute" property must be a boolean')
clock.absolute = absolute
if self._version >= 201:
if '$return-ctype' in node:
if return_ctype_node is not None:
- raise ConfigError('cannot specify both "return-ctype" and "$return-ctype" properties of clock object: prefer "$return-ctype"')
+ raise ConfigError('clock',
+ 'cannot specify both "return-ctype" and "$return-ctype" properties: prefer "$return-ctype"')
return_ctype_prop = '$return-ctype'
return_ctype_node = node[return_ctype_prop]
clock.set_default_return_ctype()
else:
if not _is_str_prop(return_ctype_node):
- raise ConfigError('"{}" property of clock object must be a string'.format(return_ctype_prop))
+ raise ConfigError('clock',
+ '"{}" property of must be a string'.format(return_ctype_prop))
clock.return_ctype = return_ctype_node
return
if not _is_assoc_array_prop(clocks_node):
- raise ConfigError('"clocks" property (metadata) must be an associative array')
+ raise ConfigError('metadata',
+ '"clocks" property must be an associative array')
for clock_name, clock_node in clocks_node.items():
if not _is_valid_identifier(clock_name):
- raise ConfigError('invalid clock name: "{}"'.format(clock_name))
+ raise ConfigError('metadata',
+ 'invalid clock name: "{}"'.format(clock_name))
if clock_name in self._clocks:
- raise ConfigError('duplicate clock "{}"'.format(clock_name))
+ raise ConfigError('metadata',
+ 'duplicate clock "{}"'.format(clock_name))
try:
clock = self._create_clock(clock_node)
- except Exception as e:
- raise ConfigError('cannot create clock "{}"'.format(clock_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('metadata',
+ 'cannot create clock "{}"'.format(clock_name))
+ raise
clock.name = clock_name
self._clocks[clock_name] = clock
return env
if not _is_assoc_array_prop(env_node):
- raise ConfigError('"env" property (metadata) must be an associative array')
+ raise ConfigError('metadata',
+ '"env" property must be an associative array')
for env_name, env_value in env_node.items():
if env_name in env:
- raise ConfigError('duplicate environment variable "{}"'.format(env_name))
+ raise ConfigError('metadata',
+ 'duplicate environment variable "{}"'.format(env_name))
if not _is_valid_identifier(env_name):
- raise ConfigError('invalid environment variable name: "{}"'.format(env_name))
+ raise ConfigError('metadata',
+ 'invalid environment variable name: "{}"'.format(env_name))
if not _is_int_prop(env_value) and not _is_str_prop(env_value):
- raise ConfigError('invalid environment variable value ("{}"): expecting integer or string'.format(env_name))
+ raise ConfigError('metadata',
+ 'invalid environment variable value ("{}"): expecting integer or string'.format(env_name))
env[env_name] = env_value
if self._version >= 201:
if '$log-levels' in metadata_node:
if log_levels_node is not None:
- raise ConfigError('cannot specify both "log-levels" and "$log-levels" properties of metadata object: prefer "$log-levels"')
+ raise ConfigError('metadata',
+ 'cannot specify both "log-levels" and "$log-levels" properties of metadata object: prefer "$log-levels"')
log_levels_prop = '$log-levels'
log_levels_node = metadata_node[log_levels_prop]
return
if not _is_assoc_array_prop(log_levels_node):
- raise ConfigError('"{}" property (metadata) must be an associative array'.format(log_levels_prop))
+ raise ConfigError('metadata',
+ '"{}" property (metadata) must be an associative array'.format(log_levels_prop))
for ll_name, ll_value in log_levels_node.items():
if ll_name in self._log_levels:
- raise ConfigError('duplicate log level entry "{}"'.format(ll_name))
+ raise ConfigError('"{}" property"'.format(log_levels_prop),
+ 'duplicate entry "{}"'.format(ll_name))
if not _is_int_prop(ll_value):
- raise ConfigError('invalid log level entry ("{}"): expecting an integer'.format(ll_name))
+ raise ConfigError('"{}" property"'.format(log_levels_prop),
+ 'invalid entry ("{}"): expecting an integer'.format(ll_name))
if ll_value < 0:
- raise ConfigError('invalid log level entry ("{}"): log level value must be positive'.format(ll_name))
+ raise ConfigError('"{}" property"'.format(log_levels_prop),
+ 'invalid entry ("{}"): value must be positive'.format(ll_name))
self._log_levels[ll_name] = ll_value
trace = metadata.Trace()
if 'trace' not in metadata_node:
- raise ConfigError('missing "trace" property (metadata)')
+ raise ConfigError('metadata', 'missing "trace" property')
trace_node = metadata_node['trace']
if not _is_assoc_array_prop(trace_node):
- raise ConfigError('"trace" property (metadata) must be an associative array')
+ raise ConfigError('metadata',
+ '"trace" property must be an associative array')
unk_prop = _get_first_unknown_prop(trace_node, [
'byte-order',
])
if unk_prop:
- raise ConfigError('unknown trace object property: "{}"'.format(unk_prop))
+ raise ConfigError('trace',
+ 'unknown property: "{}"'.format(unk_prop))
# set byte order (already parsed)
trace.byte_order = self._bo
uuidp = trace_node['uuid']
if not _is_str_prop(uuidp):
- raise ConfigError('"uuid" property of trace object must be a string')
+ raise ConfigError('trace',
+ '"uuid" property must be a string')
if uuidp == 'auto':
uuidp = uuid.uuid1()
try:
uuidp = uuid.UUID(uuidp)
except:
- raise ConfigError('malformed UUID (trace object): "{}"'.format(uuidp))
+ raise ConfigError('trace',
+ 'malformed UUID: "{}"'.format(uuidp))
trace.uuid = uuidp
if 'packet-header-type' in trace_node and trace_node['packet-header-type'] is not None:
try:
ph_type = self._create_type(trace_node['packet-header-type'])
- except Exception as e:
- raise ConfigError('cannot create packet header type (trace)', e)
+ except ConfigError as exc:
+ exc.append_ctx('trace',
+ 'cannot create packet header type')
+ raise
trace.packet_header_type = ph_type
event = metadata.Event()
if not _is_assoc_array_prop(event_node):
- raise ConfigError('event objects must be associative arrays')
+ raise ConfigError('event',
+ 'expecting associative array')
unk_prop = _get_first_unknown_prop(event_node, [
'log-level',
])
if unk_prop:
- raise ConfigError('unknown event object property: "{}"'.format(unk_prop))
+ raise ConfigError('event',
+ 'unknown property: "{}"'.format(unk_prop))
if 'log-level' in event_node and event_node['log-level'] is not None:
ll_node = event_node['log-level']
ll_value = self._lookup_log_level(event_node['log-level'])
if ll_value is None:
- raise ConfigError('cannot find log level "{}"'.format(ll_node))
+ raise ConfigError('event\'s "log-level" property',
+ 'cannot find log level "{}"'.format(ll_node))
ll = metadata.LogLevel(event_node['log-level'], ll_value)
elif _is_int_prop(ll_node):
if ll_node < 0:
- raise ConfigError('invalid log level value {}: value must be positive'.format(ll_node))
+ raise ConfigError('event\'s "log-level" property',
+ 'invalid value {}: value must be positive'.format(ll_node))
ll = metadata.LogLevel(None, ll_node)
else:
- raise ConfigError('"log-level" property must be either a string or an integer')
+ raise ConfigError('event\'s "log-level" property',
+ 'must be either a string or an integer')
event.log_level = ll
try:
t = self._create_type(event_node['context-type'])
- except Exception as e:
- raise ConfigError('cannot create event\'s context type object', e)
+ except ConfigError as exc:
+ exc.append_ctx('event',
+ 'cannot create context type object')
+ raise
event.context_type = t
if 'payload-type' in event_node and event_node['payload-type'] is not None:
try:
t = self._create_type(event_node['payload-type'])
- except Exception as e:
- raise ConfigError('cannot create event\'s payload type object', e)
+ except ConfigError as exc:
+ exc.append_ctx('event',
+ 'cannot create payload type object')
+ raise
event.payload_type = t
if unk_prop == '$default':
add = ' (use version 2.2 or greater)'
- raise ConfigError('unknown stream object property{}: "{}"'.format(add, unk_prop))
+ raise ConfigError('stream',
+ 'unknown property{}: "{}"'.format(add, unk_prop))
if 'packet-context-type' in stream_node and stream_node['packet-context-type'] is not None:
try:
t = self._create_type(stream_node['packet-context-type'])
- except Exception as e:
- raise ConfigError('cannot create stream\'s packet context type object', e)
+ except ConfigError as exc:
+ exc.append_ctx('stream',
+ 'cannot create packet context type object')
+ raise
stream.packet_context_type = t
if 'event-header-type' in stream_node and stream_node['event-header-type'] is not None:
try:
t = self._create_type(stream_node['event-header-type'])
- except Exception as e:
- raise ConfigError('cannot create stream\'s event header type object', e)
+ except ConfigError as exc:
+ exc.append_ctx('stream',
+ 'cannot create event header type object')
+ raise
stream.event_header_type = t
if 'event-context-type' in stream_node and stream_node['event-context-type'] is not None:
try:
t = self._create_type(stream_node['event-context-type'])
- except Exception as e:
- raise ConfigError('cannot create stream\'s event context type object', e)
+ except ConfigError as exc:
+ exc.append_ctx('stream',
+ 'cannot create event context type object')
+ raise
stream.event_context_type = t
if 'events' not in stream_node:
- raise ConfigError('missing "events" property in stream object')
+ raise ConfigError('stream',
+ 'missing "events" property')
events = stream_node['events']
if events is not None:
if not _is_assoc_array_prop(events):
- raise ConfigError('"events" property of stream object must be an associative array')
+ raise ConfigError('stream',
+ '"events" property must be an associative array')
if not events:
- raise ConfigError('at least one event is needed within a stream object')
+ raise ConfigError('stream', 'at least one event is needed')
cur_id = 0
for ev_name, ev_node in events.items():
try:
ev = self._create_event(ev_node)
- except Exception as e:
- raise ConfigError('cannot create event "{}"'.format(ev_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('stream',
+ 'cannot create event "{}"'.format(ev_name))
+ raise
ev.id = cur_id
ev.name = ev_name
default_node = stream_node['$default']
if not _is_bool_prop(default_node):
- raise ConfigError('invalid "$default" property in stream object: expecting a boolean')
+ raise ConfigError('stream',
+ 'invalid "$default" property: expecting a boolean')
if default_node:
if self._meta.default_stream_name is not None and self._meta.default_stream_name != stream_name:
fmt = 'cannot specify more than one default stream (default stream already set to "{}")'
- raise ConfigError(fmt.format(self._meta.default_stream_name))
+ raise ConfigError('stream',
+ fmt.format(self._meta.default_stream_name))
self._meta.default_stream_name = stream_name
streams = collections.OrderedDict()
if 'streams' not in metadata_node:
- raise ConfigError('missing "streams" property (metadata)')
+ raise ConfigError('metadata',
+ 'missing "streams" property')
streams_node = metadata_node['streams']
if not _is_assoc_array_prop(streams_node):
- raise ConfigError('"streams" property (metadata) must be an associative array')
+ raise ConfigError('metadata',
+ '"streams" property must be an associative array')
if not streams_node:
- raise ConfigError('at least one stream is needed (metadata)')
+ raise ConfigError('metadata\'s "streams" property',
+ 'at least one stream is needed')
cur_id = 0
for stream_name, stream_node in streams_node.items():
try:
stream = self._create_stream(stream_name, stream_node)
- except Exception as e:
- raise ConfigError('cannot create stream "{}"'.format(stream_name), e)
+ except ConfigError as exc:
+ exc.append_ctx('metadata',
+ 'cannot create stream "{}"'.format(stream_name))
+ raise
stream.id = cur_id
stream.name = str(stream_name)
self._meta = metadata.Metadata()
if 'metadata' not in root:
- raise ConfigError('missing "metadata" property (configuration)')
+ raise ConfigError('configuration',
+ 'missing "metadata" property')
metadata_node = root['metadata']
if not _is_assoc_array_prop(metadata_node):
- raise ConfigError('"metadata" property (configuration) must be an associative array')
+ raise ConfigError('configuration\'s "metadata" property',
+ 'must be an associative array')
known_props = [
'type-aliases',
if unk_prop == '$default-stream':
add = ' (use version 2.2 or greater)'
- raise ConfigError('unknown metadata property{}: "{}"'.format(add, unk_prop))
+ raise ConfigError('metadata',
+ 'unknown property{}: "{}"'.format(add, unk_prop))
if '$default-stream' in metadata_node and metadata_node['$default-stream'] is not None:
default_stream_node = metadata_node['$default-stream']
if not _is_str_prop(default_stream_node):
- raise ConfigError('invalid "$default-stream" property (metadata): expecting a string')
+ raise ConfigError('metadata\'s "$default-stream" property',
+ 'expecting a string')
self._meta.default_stream_name = default_stream_node
def _get_version(self, root):
if 'version' not in root:
- raise ConfigError('missing "version" property (configuration)')
+ raise ConfigError('configuration',
+ 'missing "version" property')
version_node = root['version']
if not _is_str_prop(version_node):
- raise ConfigError('"version" property (configuration) must be a string')
+ raise ConfigError('configuration\'s "version" property',
+ 'must be a string')
version_node = version_node.strip()
if version_node not in ['2.0', '2.1', '2.2']:
- raise ConfigError('unsupported version ({}): versions 2.0, 2.1, and 2.2 are supported'.format(version_node))
+ raise ConfigError('configuration',
+ 'unsupported version ({}): versions 2.0, 2.1, and 2.2 are supported'.format(version_node))
# convert version string to comparable version integer
parts = version_node.split('.')
return def_prefix
if not _is_str_prop(prefix_node):
- raise ConfigError('"prefix" property (configuration) must be a string')
+ raise ConfigError('configuration\'s "prefix" property',
+ 'must be a string')
if not _is_valid_identifier(prefix_node):
- raise ConfigError('"prefix" property (configuration) must be a valid C identifier')
+ raise ConfigError('configuration\'s "prefix" property',
+ 'must be a valid C identifier')
return prefix_node
options_node = root['options']
if not _is_assoc_array_prop(options_node):
- raise ConfigError('"options" property (configuration) must be an associative array')
+ raise ConfigError('configuration\'s "options" property',
+ 'must be an associative array')
known_props = [
'gen-prefix-def',
unk_prop = _get_first_unknown_prop(options_node, known_props)
if unk_prop:
- raise ConfigError('unknown configuration option property: "{}"'.format(unk_prop))
+ raise ConfigError('configuration\'s "options" property',
+ 'unknown property: "{}"'.format(unk_prop))
if 'gen-prefix-def' in options_node and options_node['gen-prefix-def'] is not None:
gen_prefix_def_node = options_node['gen-prefix-def']
if not _is_bool_prop(gen_prefix_def_node):
- raise ConfigError('invalid configuration option "gen-prefix-def": expecting a boolean')
+ raise ConfigError('configuration\'s "options" property',
+ 'invalid option "gen-prefix-def": expecting a boolean')
cfg_options.gen_prefix_def = gen_prefix_def_node
gen_default_stream_def_node = options_node['gen-default-stream-def']
if not _is_bool_prop(gen_default_stream_def_node):
- raise ConfigError('invalid configuration option "gen-default-stream-def": expecting a boolean')
+ raise ConfigError('configuration\'s "options" property',
+ 'invalid option "gen-default-stream-def": expecting a boolean')
cfg_options.gen_default_stream_def = gen_default_stream_def_node
if norm_path in self._include_stack:
base_path = self._get_last_include_file()
- raise ConfigError('in "{}": cannot recursively include file "{}"'.format(base_path, norm_path))
+ raise ConfigError('in "{}"',
+ 'cannot recursively include file "{}"'.format(base_path, norm_path))
self._include_stack.append(norm_path)
if not self._ignore_include_not_found:
base_path = self._get_last_include_file()
- raise ConfigError('in "{}": cannot include file "{}": file not found in include directories'.format(base_path, yaml_path))
+ raise ConfigError('in "{}"',
+ 'cannot include file "{}": file not found in include directories'.format(base_path, yaml_path))
return None
if _is_array_prop(include_node):
for include_path in include_node:
if not _is_str_prop(include_path):
- raise ConfigError('invalid include property: expecting array of strings')
+ raise ConfigError('"$include" property',
+ 'expecting array of strings')
return include_node
- raise ConfigError('invalid include property: expecting string or array of strings')
+ raise ConfigError('"$include" property',
+ 'expecting string or array of strings')
def _update_node(self, base_node, overlay_node):
for olay_key, olay_value in overlay_node.items():
process_base_include_cb,
process_children_include_cb=None):
if not _is_assoc_array_prop(last_overlay_node):
- raise ConfigError('{} objects must be associative arrays'.format(name))
+ raise ConfigError('"$include" property',
+ '{} objects must be associative arrays'.format(name))
# process children inclusions first
if process_children_include_cb:
# recursively process includes
try:
overlay_node = process_base_include_cb(overlay_node)
- except Exception as e:
- raise ConfigError('in "{}"'.format(cur_base_path), e)
+ except ConfigError as exc:
+ exc.append_ctx('in "{}"'.format(cur_base_path))
+ raise
# pop include stack now that we're done including
del self._include_stack[-1]
events_node = stream_node['events']
if not _is_assoc_array_prop(events_node):
- raise ConfigError('"events" property must be an associative array')
+ raise ConfigError('"$include" property',
+ '"events" property must be an associative array')
events_node_keys = list(events_node.keys())
try:
events_node[key] = self._process_event_include(event_node)
- except Exception as e:
- raise ConfigError('cannot process includes of event object "{}"'.format(key), e)
+ except ConfigError as exc:
+ exc.append_ctx('"$include" property',
+ 'cannot process includes of event object "{}"'.format(key))
+ raise
return self._process_node_include(stream_node, 'stream',
self._process_stream_include,
clocks_node = metadata_node['clocks']
if not _is_assoc_array_prop(clocks_node):
- raise ConfigError('"clocks" property (metadata) must be an associative array')
+ raise ConfigError('"$include" property',
+ '"clocks" property must be an associative array')
clocks_node_keys = list(clocks_node.keys())
try:
clocks_node[key] = self._process_clock_include(clock_node)
- except Exception as e:
- raise ConfigError('cannot process includes of clock object "{}"'.format(key), e)
+ except ConfigError as exc:
+ exc.append_ctx('"$include" property',
+ 'cannot process includes of clock object "{}"'.format(key))
+ raise
if 'streams' in metadata_node:
streams_node = metadata_node['streams']
if not _is_assoc_array_prop(streams_node):
- raise ConfigError('"streams" property (metadata) must be an associative array')
+ raise ConfigError('"$include" property',
+ '"streams" property must be an associative array')
streams_node_keys = list(streams_node.keys())
try:
streams_node[key] = self._process_stream_include(stream_node)
- except Exception as e:
- raise ConfigError('cannot process includes of stream object "{}"'.format(key), e)
+ except ConfigError as exc:
+ exc.append_ctx('"$include" property',
+ 'cannot process includes of stream object "{}"'.format(key))
+ raise
return self._process_node_include(metadata_node, 'metadata',
self._process_metadata_include,
with open(yaml_path, 'r') as f:
node = yaml.load(f, OLoader)
except (OSError, IOError) as e:
- raise ConfigError('cannot open file "{}"'.format(yaml_path))
- except Exception as e:
- raise ConfigError('unknown error while trying to load file "{}"'.format(yaml_path), e)
+ raise ConfigError('configuration',
+ 'cannot open file "{}"'.format(yaml_path))
+ except ConfigError as exc:
+ exc.append_ctx('configuration',
+ 'unknown error while trying to load file "{}"'.format(yaml_path))
+ raise
# loaded node must be an associate array
if not _is_assoc_array_prop(node):
- raise ConfigError('root of YAML file "{}" must be an associative array'.format(yaml_path))
+ raise ConfigError('configuration',
+ 'root of YAML file "{}" must be an associative array'.format(yaml_path))
return node
try:
root = self._yaml_ordered_load(yaml_path)
- except Exception as e:
- raise ConfigError('cannot parse YAML file "{}"'.format(yaml_path), e)
+ except ConfigError as exc:
+ exc.append_ctx('configuration',
+ 'cannot parse YAML file "{}"'.format(yaml_path))
+ raise
if not _is_assoc_array_prop(root):
- raise ConfigError('configuration must be an associative array')
+ raise ConfigError('configuration',
+ 'must be an associative array')
# get the config version
self._version = self._get_version(root)
if unk_prop == 'options':
add = ' (use version 2.2 or greater)'
- raise ConfigError('unknown configuration property{}: "{}"'.format(add, unk_prop))
+ raise ConfigError('configuration',
+ 'unknown property{}: "{}"'.format(add, unk_prop))
# process includes if supported
if self._version >= 201:
cfg = parser.parse(path)
return cfg
- except Exception as e:
- raise ConfigError('cannot create configuration from YAML file "{}"'.format(path), e)
+ except ConfigError as exc:
+ exc.append_ctx('configuration',
+ 'cannot create configuration from YAML file "{}"'.format(path))
+ raise