def _write(self, data: SerializeTypes, codec: Codec, context: 'VerediContext') -> StringIO: ''' Write data from a single data stream. Returns: Output of yaml.safe_dump(). Mix of: - yaml objects - our subclasses of yaml objects - and python objects Raises: - exceptions.WriteError Maybes: - Other yaml/stream errors? ''' self._log_data_processing(self.dotted, "Writing '{}' to stream...", type(data), context=context) serialized = StringIO() try: yaml.safe_dump(data, default_sequence=yaml.SequenceStyle.DEFAULT, stream=serialized) # TODO [2020-07-04]: may need to evaluate this in some way to get # it past its lazy writing... I want to catch any yaml exceptions # here and not let them infect unrelated code. except yaml.YAMLError as yaml_error: serialized = None msg = 'YAML failed while writing the data.' self._log_data_processing(self.dotted, msg, context=context, success=False) error = exceptions.WriteError(msg, context=context, data={ 'data': data, }) raise log.exception(error, msg, context=context) from yaml_error # Apparently yaml doesn't give us the spot in the stream it started # writing, so rewind. serialized.seek(0) self._log_data_processing(self.dotted, "Wrote '{}' to YAML!", type(data), context=context, success=True) return serialized
def _write_all(self, data: SerializeTypes, codec: Codec, context: 'VerediContext') -> StringIO: ''' Write data from a single data stream. Returns: Output of yaml.safe_dump_all(). Mix of: - yaml objects - our subclasses of yaml objects - and python objects Raises: - exceptions.WriteError Maybes: - Other yaml/stream errors? ''' self._log_data_processing(self.dotted, "Writing all '{}' to stream...", type(data), context=context) serialized = StringIO() try: yaml.safe_dump_all(data, default_sequence=yaml.SequenceStyle.DEFAULT, stream=serialized) except yaml.YAMLError as yaml_error: serialized = None msg = 'YAML failed while writing all the data.' self._log_data_processing(self.dotted, msg, context=context, success=False) error = exceptions.WriteError(msg, context=context, data={ 'data': data, }) raise log.exception(error, msg, context=context) from yaml_error # Apparently yaml doesn't give us the spot in the stream it started # writing, so rewind. serialized.seek(0) self._log_data_processing(self.dotted, "Wrote '{}' to YAML!", type(data), context=context, success=True) return serialized
def _write(self, data: SerializeTypes, codec: Codec, context: 'VerediContext') -> StringIO: ''' Write data to a stream. Returns: The stream with the serialized data in it. Raises: - exceptions.WriteError - wrapped lib/module errors ''' self._log_data_processing(self.dotted, "Writing '{}' to stream...", type(data), context=context) serialized = StringIO() try: self._json_dump(data, serialized, context) except (TypeError, OverflowError, ValueError) as json_error: serialized = None # data_pretty = pretty.indented(data) msg = f"Error writing data '{type(data)}' to stream." self._log_data_processing(self.dotted, msg, context=context, success=False) error = exceptions.WriteError(msg, context=context, data={ 'data': data, }) raise log.exception(error, msg, context=context) from json_error self._log_data_processing(self.dotted, "Wrote '{}' to JSON!", type(data), context=context, success=True) return serialized
def serialize_all(self, data: SerializeTypes, codec: Codec, context: 'VerediContext') -> StringIO: ''' Serializes data from an iterable of data objects. Each will be a separate yaml doc in the output. Raises: - exceptions.WriteError ''' self._log_data_processing(self.dotted, "Serializing all from '{}'...", type(data), context=context) to_serialize = self._serialize_prep(data, codec, context) self._context_data(context, DataAction.SAVE, codec) output = self._write_all(to_serialize, codec, context) if not output: msg = (f"Serializing all yaml from data " "resulted in no output: {output}") self._log_data_processing(self.dotted, msg, context=context, success=False) error = exceptions.WriteError(msg, context=context, data={ 'data': data, }) raise log.exception(error, msg, context=context) # TODO: Here is where we'd check for sanity and stuff? self._log_data_processing(self.dotted, "Serialized all from '{}'!", type(data), context=context, success=True) return output
def serialize(self, data: SerializeTypes, codec: Codec, context: 'VerediContext') -> StringIO: ''' Serializes data from a single data object. Raises: - exceptions.WriteError ''' self._log_data_processing(self.dotted, "Serializing from '{}'...", type(data), context=context) self._context_data(context, DataAction.SAVE, codec) to_serialize = self._serialize_prep(data, codec, context) output = self._write(to_serialize, codec, context) if not output: msg = f"Serializing yaml from data resulted in no output: {output}" self._log_data_processing(self.dotted, msg, context=context, success=False) error = exceptions.WriteError(msg, context=context, data={ 'data': data, }) raise log.exception(error, msg, context=context) self._log_data_processing(self.dotted, "Serialized from '{}'!", type(data), context=context, success=True) return output
def _serialize_prep(self, data: SerializeTypes, codec: Codec, context: 'VerediContext') -> Mapping[str, Any]: ''' Tries to turn the various possibilities for data (list, dict, etc) into something ready for json to serialize. ''' self._log_data_processing(self.dotted, "Serialize preparation...", context=context) serialized = None if null_or_none(data): self._log_data_processing(self.dotted, "No data to prep.", context=context) return serialized # Is it just an Encodable object? if isinstance(data, Encodable): self._log_data_processing(self.dotted, "Encoding `Encodable` data " "for serialization.", context=context) serialized = codec.encode(data) return serialized # Is it a simple type? if text.serialize_claim(data) or time.serialize_claim(data): # Let json handle it. serialized = data return serialized if paths.serialize_claim(data): serialized = paths.serialize(data) return serialized if numbers.serialize_claim(data): serialized = numbers.serialize(data) return serialized # Mapping? with contextlib.suppress(AttributeError, TypeError): # Do the thing that spawns the exception before # we log about doing the thing... keys = data.keys() self._log_data_processing(self.dotted, "Prepping `Mapping` of data " "for serialization.", context=context) serialized = {} for each in keys: # TODO [2020-07-29]: Change to non-recursive? serialized[str(each)] = self._serialize_prep(data[each], codec, context) return serialized # Iterable with contextlib.suppress(AttributeError, TypeError): # Do the thing that spawns the exception before # we log about doing the thing... iterable = iter(data) self._log_data_processing(self.dotted, "Prepping `Iterable` of data " "for serialization.", context=context) serialized = [] for each in iterable: # TODO [2020-07-29]: Change to non-recursive? serialized.append(self._serialize_prep(each, codec, context)) return serialized # Falling through to here is bad; raise Exception. msg = f"Don't know how to process '{type(data)}' data." self._log_data_processing(self.dotted, msg, context=context, success=False) error = exceptions.WriteError(msg, context=context, data={ 'data': data, }) raise log.exception(error, msg, context=context)