Source code for gemseo.utils.string_tools
# -*- coding: utf-8 -*-
# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Contributors:
# INITIAL AUTHORS - initial API and implementation and/or initial
# documentation
# :author: Matthias De Lozzo
# :author: Antoine Dechaume
# OTHER AUTHORS - MACROSCOPIC CHANGES
"""
Pretty string utils
===================
"""
from collections import namedtuple
from contextlib import contextmanager
from gemseo.utils.py23_compat import PY2
if PY2:
from collections import Iterable, Mapping
else:
from collections.abc import Iterable, Mapping
# to store the raw ingredients of a string to be formatted later
MessageLine = namedtuple("MessageLine", "str_format level args kwargs")
[docs]def pretty_repr(obj, **kwargs):
"""String representation of an object.
:param obj: object.
:return: pretty string representation.
:rtype: str
"""
delimiter = kwargs.get("delimiter", ", ")
if isinstance(obj, Mapping):
return delimiter.join(
["{}={}".format(key, repr(val)) for key, val in sorted(obj.items())]
)
if isinstance(obj, Iterable):
return delimiter.join([str(val) for val in obj])
return repr(obj)
[docs]class MultiLineString(object):
"""Multi-line string lazy evaluator.
The creation of the string is postponed to when an instance is stringified through
the __repr__ method. This is mainly used for logging complex strings or objects
where the string evaluation cost may be avoided when the logging level dismisses a
logging message.
"""
INDENTATION = " " * 3
DEFAULT_LEVEL = 0
def __init__(self):
self.__lines = []
self.__level = None
self.reset()
[docs] def add(self, str_format, *args, **kwargs):
"""Add a line.
:param str str_format: string to be process by the format() method.
:param args: args passed to the format() method.
:param kwargs: kwargs passed to the format() method.
"""
self.__lines.append(MessageLine(str_format, self.__level, args, kwargs))
[docs] def reset(self):
"""Reset the indentation."""
self.__level = self.DEFAULT_LEVEL
[docs] def indent(self):
"""Increase the indentation."""
self.__level += 1
[docs] def dedent(self):
"""Decrease the indentation."""
if self.__level > 0:
self.__level -= 1
def __repr__(self):
lines = []
for line in self.__lines:
str_format = self.INDENTATION * line.level + line.str_format
lines.append(str_format.format(*line.args, **line.kwargs))
return "\n".join(lines)
[docs] @classmethod
@contextmanager
def offset(cls):
cls.DEFAULT_LEVEL += 1
try:
yield
finally:
cls.DEFAULT_LEVEL -= 1