def test__get_attribute_csv_data(request, instance_postgresql, delimiter, wrap_all_strings, wrapper_character, hybrid_value, expected_result): target = instance_postgresql[0][0] target.hybrid = hybrid_value attributes = [ x for x in get_attribute_names(target, include_callable=False, include_nested=False, include_private=True, include_utilities=False) if x[0:2] != '__' ] result = target._get_attribute_csv_data( attributes, is_dumping=True, delimiter=delimiter, wrap_all_strings=wrap_all_strings, wrapper_character=wrapper_character) print(result) assert result == expected_result
def test__get_attribute_csv_header(request, instance_postgresql, delimiter, expected_result): target = instance_postgresql[0][0] attributes = [ x for x in get_attribute_names(target, include_callable=False, include_nested=False, include_private=True, include_utilities=False) if x[0:2] != '__' ] if delimiter is not None: result = target._get_attribute_csv_header(attributes, delimiter=delimiter) else: result = target._get_attribute_csv_header(attributes) print(result) assert result == expected_result
def test_get_attribute_names(model_complex_postgresql, instance_postgresql, use_instance, include_callable, include_nested, include_private, include_special, include_utilities, expected_result): if use_instance: target = instance_postgresql[0][0] else: target = model_complex_postgresql[0] result = get_attribute_names(target, include_callable=include_callable, include_nested=include_nested, include_private=include_private, include_utilities=include_utilities) print(result) if sqlalchemy.__version__[2] == '9' and isinstance(expected_result, tuple): expected_result = expected_result[0] elif isinstance(expected_result, tuple): expected_result = expected_result[1] assert len(result) == expected_result
def dump_to_csv(self, include_header=False, delimiter='|', wrap_all_strings=False, null_text='None', wrapper_character="'", double_wrapper_character_when_nested=False, escape_character="\\", line_terminator='\r\n', config_set=None): r"""Retrieve a :term:`CSV <Comma-Separated Value (CSV)>` representation of the object, *with all attributes* serialized regardless of configuration. .. caution:: Nested objects (such as :term:`relationships <relationship>` or :term:`association proxies <association proxy>`) will **not** be serialized. .. note:: This method ignores any ``display_name`` contributed on the :class:`AttributeConfiguration`. :param include_header: If ``True``, will include a header row with column labels. If ``False``, will not include a header row. Defaults to ``True``. :type include_header: :class:`bool <python:bool>` :param delimiter: The delimiter used between columns. Defaults to ``|``. :type delimiter: :class:`str <python:str>` :param wrap_all_strings: If ``True``, wraps any string data in the ``wrapper_character``. If ``None``, only wraps string data if it contains the ``delimiter``. Defaults to ``False``. :type wrap_all_strings: :class:`bool <python:bool>` :param null_text: The text value to use in place of empty values. Only applies if ``wrap_empty_values`` is ``True``. Defaults to ``'None'``. :type null_text: :class:`str <python:str>` :param wrapper_character: The string used to wrap string values when wrapping is necessary. Defaults to ``'``. :type wrapper_character: :class:`str <python:str>` :param double_wrapper_character_when_nested: If ``True``, will double the ``wrapper_character`` when it is found inside a column value. If ``False``, will precede the ``wrapper_character`` by the ``escape_character`` when it is found inside a column value. Defaults to ``False``. :type double_wrapper_character_when_nested: :class:`bool <python:bool>` :param escape_character: The character to use when escaping nested wrapper characters. Defaults to ``\``. :type escape_character: :class:`str <python:str>` :param line_terminator: The character used to mark the end of a line. Defaults to ``\r\n``. :type line_terminator: :class:`str <python:str>` :param config_set: If not :obj:`None <python:None>`, the named configuration set to use. Defaults to :obj:`None <python:None>`. :type config_set: :class:`str <python:str>` / :obj:`None <python:None>` :returns: Data from the object in CSV format ending in a newline (``\n``). :rtype: :class:`str <python:str>` """ # pylint: disable=line-too-long attributes = [ x for x in get_attribute_names(self, include_callable=False, include_nested=False, include_private=True, include_special=False, include_utilities=False) if x[0:2] != '__' ] if include_header: return self._get_attribute_csv_header(attributes, delimiter = delimiter) + \ self._get_attribute_csv_data(attributes, is_dumping = True, delimiter = delimiter, wrap_all_strings = wrap_all_strings, null_text = null_text, wrapper_character = wrapper_character, double_wrapper_character_when_nested = double_wrapper_character_when_nested, escape_character = escape_character, line_terminator = line_terminator, config_set = config_set) return self._get_attribute_csv_data( attributes, is_dumping=True, delimiter=delimiter, wrap_all_strings=wrap_all_strings, null_text=null_text, wrapper_character=wrapper_character, double_wrapper_character_when_nested= double_wrapper_character_when_nested, escape_character=escape_character, line_terminator=line_terminator, config_set=config_set)
def _to_dict(self, format, max_nesting=0, current_nesting=0, is_dumping=False, config_set=None): """Return a :class:`dict <python:dict>` representation of the object. .. warning:: This method is an **intermediate** step that is used to produce the contents for certain public JSON, YAML, and :class:`dict <python:dict>` serialization methods. It should not be called directly. :param format: The format to which the :class:`dict <python:dict>` will ultimately be serialized. Accepts: ``'csv'``, ``'json'``, ``'yaml'``, and ``'dict'``. :type format: :class:`str <python:str>` :param max_nesting: The maximum number of levels that the resulting :class:`dict <python:dict>` object can be nested. If set to ``0``, will not nest other serializable objects. Defaults to ``0``. :type max_nesting: :class:`int <python:int>` :param current_nesting: The current nesting level at which the :class:`dict <python:dict>` representation will reside. Defaults to ``0``. :type current_nesting: :class:`int <python:int>` :param is_dumping: If ``True``, retrieves all attributes except callables, utilities, and specials (``__<name>``). If ``False``, only retrieves those that have JSON serialization enabled. Defaults to ``False``. :type is_dumping: :class:`bool <python:bool>` :param config_set: If not :obj:`None <python:None>`, the named configuration set to use when processing the input. Defaults to :obj:`None <python:None>`. :type config_set: :class:`str <python:str>` / :obj:`None <python:None>` :returns: A :class:`dict <python:dict>` representation of the object. :rtype: :class:`dict <python:dict>` :raises InvalidFormatError: if ``format`` is not recognized :raises SerializableAttributeError: if attributes is empty :raises UnsupportedSerializationError: if unable to serialize a value :raises MaximumNestingExceededError: if ``current_nesting`` is greater than ``max_nesting`` :raises MaximumNestingExceededWarning: if an attribute requires nesting beyond ``max_nesting`` """ # pylint: disable=too-many-branches next_nesting = current_nesting + 1 if format not in ['csv', 'json', 'yaml', 'dict']: raise InvalidFormatError("format '%s' not supported" % format) if current_nesting > max_nesting: raise MaximumNestingExceededError( 'current nesting level (%s) exceeds maximum %s' % (current_nesting, max_nesting)) dict_object = dict_() if format == 'csv': attribute_getter = self.get_csv_serialization_config elif format == 'json': attribute_getter = self.get_json_serialization_config elif format == 'yaml': attribute_getter = self.get_yaml_serialization_config elif format == 'dict': attribute_getter = self.get_dict_serialization_config if not is_dumping: attributes = [ x for x in attribute_getter( deserialize=None, serialize=True, config_set=config_set) if hasattr(self, x.name) ] else: attribute_names = [ x for x in get_attribute_names(self, include_callable=False, include_nested=False, include_private=True, include_special=False, include_utilities=False) ] attributes = [] for item in attribute_names: attribute_config = self.get_attribute_serialization_config( item, config_set=config_set) if attribute_config is not None: on_serialize_function = attribute_config.on_serialize.get( format, None) else: on_serialize_function = None attribute = AttributeConfiguration( name=item, supports_json=True, supports_yaml=True, supports_dict=True, on_serialize=on_serialize_function) attributes.append(attribute) if not attributes: raise SerializableAttributeError( "'%s' has no '%s' serializable attributes" % (type(self.__class__), format)) for attribute in attributes: item = getattr(self, attribute.name, None) if hasattr(item, '_to_dict'): try: value = item._to_dict( format, # pylint: disable=protected-access max_nesting=max_nesting, current_nesting=next_nesting, is_dumping=is_dumping, config_set=config_set) except MaximumNestingExceededError: warnings.warn( "skipping key '%s' because maximum nesting has been exceeded" \ % attribute.name, MaximumNestingExceededWarning ) continue else: if attribute.on_serialize[format]: on_serialize_function = attribute.on_serialize[format] item = on_serialize_function(item) if checkers.is_iterable(item, forbid_literals=(str, bytes, dict)): try: value = iterable__to_dict(item, format, max_nesting=max_nesting, current_nesting=next_nesting, is_dumping=is_dumping, config_set=config_set) except MaximumNestingExceededError: warnings.warn( "skipping key '%s' because maximum nesting has been exceeded" \ % attribute.name, MaximumNestingExceededWarning ) continue except NotAnIterableError: try: value = self._get_serialized_value( format, attribute.name, config_set=config_set) except UnsupportedSerializationError as error: if is_dumping: value = getattr(self, attribute.name) else: raise error else: try: value = self._get_serialized_value( format, attribute.name, config_set=config_set) except UnsupportedSerializationError as error: if is_dumping: value = getattr(self, attribute.name) else: raise error serialized_key = attribute.display_name or attribute.name dict_object[str(serialized_key)] = value return dict_object