diff --git a/logwrap/class_decorator.py b/logwrap/class_decorator.py index 1659b24..62fcb02 100644 --- a/logwrap/class_decorator.py +++ b/logwrap/class_decorator.py @@ -26,9 +26,7 @@ class BaseDecorator(metaclass=abc.ABCMeta): Implements wrapping and __call__, wrapper getter is abstract. - Note: - wrapper getter is called only on function call, - if decorator used without braces. + .. note:: wrapper getter is called only on function call, if decorator used without braces. Usage example: diff --git a/logwrap/class_decorator.pyx b/logwrap/class_decorator.pyx index ca0c81e..b65da63 100644 --- a/logwrap/class_decorator.pyx +++ b/logwrap/class_decorator.pyx @@ -19,10 +19,19 @@ import typing cdef class BaseDecorator: - """Base class for decorators.""" + """Base class for decorators. + + Implements wrapping and __call__, wrapper getter is abstract. + + .. note:: wrapper getter is called only on function call, if decorator used without braces. + """ def __init__(self, func: typing.Optional[typing.Callable] = None) -> None: - """Decorator.""" + """Decorator. + + :param func: function to wrap + :type func: typing.Optional[typing.Callable] + """ # noinspection PyArgumentList super(BaseDecorator, self).__init__() # pylint: disable=assigning-non-slot @@ -32,7 +41,12 @@ cdef class BaseDecorator: # pylint: enable=assigning-non-slot def _get_function_wrapper(self, func: typing.Callable) -> typing.Callable: - """Here should be constructed and returned real decorator.""" + """Here should be constructed and returned real decorator. + + :param func: Wrapped function + :type func: typing.Callable + :rtype: typing.Callable + """ raise NotImplementedError() # pragma: no cover def __call__(self, *args: typing.Union[typing.Callable, typing.Any], **kwargs: typing.Any) -> typing.Any: diff --git a/logwrap/log_wrap.pxd b/logwrap/log_wrap.pxd index 5308c21..a9157b7 100644 --- a/logwrap/log_wrap.pxd +++ b/logwrap/log_wrap.pxd @@ -44,13 +44,14 @@ cdef class LogWrap(class_decorator.BaseDecorator): cdef public bint log_traceback cdef public bint log_result_obj + cdef readonly object _spec + cdef readonly object _logger + cdef list __blacklisted_names cdef list __blacklisted_exceptions - cdef object __logger - cdef object __spec cdef str _get_func_args_repr( - self, sig: inspect.Signature, args: typing.Tuple, kwargs: typing.Dict[str, typing.Any] + self, sig: inspect.Signature, tuple args, dict kwargs ) cdef void _make_done_record(self, str func_name, result: typing.Any) cdef void _make_calling_record(self, str name, str arguments, str method=?) diff --git a/logwrap/log_wrap.py b/logwrap/log_wrap.py index aaece5c..8dccde7 100644 --- a/logwrap/log_wrap.py +++ b/logwrap/log_wrap.py @@ -711,7 +711,7 @@ def logwrap( # noqa: F811 # pylint: disable=unexpected-keyword-arg, no-value-f log_traceback: bool = True, log_result_obj: bool = True ) -> typing.Union[LogWrap, typing.Callable]: - """Log function calls and return values. Python 3.4+ version. + """Log function calls and return values. :param func: function to wrap :type func: typing.Optional[typing.Callable] diff --git a/logwrap/log_wrap.pyx b/logwrap/log_wrap.pyx index 03ac63f..e82591f 100644 --- a/logwrap/log_wrap.pyx +++ b/logwrap/log_wrap.pyx @@ -63,7 +63,14 @@ class BoundParameter: empty = inspect.Parameter.empty def __init__(self, parameter: inspect.Parameter, value: typing.Any = inspect.Parameter.empty) -> None: - """Parameter-like object store BOUND with value parameter.""" + """Parameter-like object store BOUND with value parameter. + + :param parameter: parameter from signature + :type parameter: inspect.Parameter + :param value: parameter real value + :type value: typing.Any + :raises ValueError: No default value and no value + """ self._parameter = parameter if value is self.empty: @@ -105,7 +112,10 @@ class BoundParameter: # noinspection PyTypeChecker def __hash__(self) -> int: - """Block hashing.""" + """Block hashing. + + :raises TypeError: Not hashable. + """ msg = "unhashable type: '{0}'".format(self.__class__.__name__) raise TypeError(msg) @@ -150,7 +160,19 @@ class BoundParameter: def bind_args_kwargs( sig: inspect.Signature, *args: typing.Any, **kwargs: typing.Any ) -> typing.Iterator[BoundParameter]: - """Bind *args and **kwargs to signature and get Bound Parameters.""" + """Bind *args and **kwargs to signature and get Bound Parameters. + + :param sig: source signature + :type sig: inspect.Signature + :param args: not keyworded arguments + :type args: typing.Any + :param kwargs: keyworded arguments + :type kwargs: typing.Any + :return: Iterator for bound parameters with all information about it + :rtype: typing.Iterator[BoundParameter] + + .. versionadded:: 3.3.0 + """ bound = sig.bind(*args, **kwargs).arguments parameters = list(sig.parameters.values()) for param in parameters: @@ -176,7 +198,42 @@ cdef class LogWrap(class_decorator.BaseDecorator): bint log_traceback=True, bint log_result_obj=True ) -> None: - """Log function calls and return values.""" + """Log function calls and return values. + + :param func: function to wrap + :type func: typing.Optional[typing.Callable] + :param log: logger object for decorator, by default used 'logwrap' + :type log: logging.Logger + :param log_level: log level for successful calls + :type log_level: int + :param exc_level: log level for exception cases + :type exc_level: int + :param max_indent: maximum indent before classic `repr()` call. + :type max_indent: int + :param spec: callable object used as spec for arguments bind. + This is designed for the special cases only, + when impossible to change signature of target object, + but processed/redirected signature is accessible. + Note: this object should provide fully compatible + signature with decorated function, or arguments bind + will be failed! + :type spec: typing.Optional[typing.Callable] + :param blacklisted_names: Blacklisted argument names. Arguments with this names will be skipped in log. + :type blacklisted_names: typing.Optional[typing.Iterable[str]] + :param blacklisted_exceptions: list of exception, which should be re-raised without producing log record. + :type blacklisted_exceptions: typing.Optional[typing.Iterable[typing.Type[Exception]]] + :param log_call_args: log call arguments before executing wrapped function. + :type log_call_args: bool + :param log_call_args_on_exc: log call arguments if exception raised. + :type log_call_args_on_exc: bool + :param log_traceback: log traceback on excaption in addition to failure info + :type log_traceback: bool + :param log_result_obj: log result of function call. + :type log_result_obj: bool + + .. versionchanged:: 3.3.0 Extract func from log and do not use Union. + .. versionchanged:: 5.1.0 log_traceback parameter + """ super(LogWrap, self).__init__(func=func) self.log_level = log_level @@ -198,9 +255,8 @@ cdef class LogWrap(class_decorator.BaseDecorator): else: self.__blacklisted_exceptions = list(blacklisted_exceptions) - self.__logger = log - - self.__spec = spec or self._func + self._logger = log + self._spec = spec or self._func # We are not interested to pass any arguments to object @@ -214,16 +270,6 @@ cdef class LogWrap(class_decorator.BaseDecorator): """List of exceptions to re-raise without log.""" return self.__blacklisted_exceptions - @property - def _logger(self) -> logging.Logger: - """Logger instance.""" - return self.__logger - - @property - def _spec(self) -> typing.Optional[typing.Callable]: - """Spec for function arguments.""" - return self.__spec - def __repr__(self) -> str: """Repr for debug purposes.""" return ( @@ -243,15 +289,49 @@ cdef class LogWrap(class_decorator.BaseDecorator): def pre_process_param( self, arg: BoundParameter ) -> typing.Union[BoundParameter, typing.Tuple[BoundParameter, typing.Any], None]: - """Process parameter for the future logging.""" + """Process parameter for the future logging. + + :param arg: bound parameter + :type arg: BoundParameter + :return: value, value override for logging or None if argument should not be logged. + :rtype: typing.Union[BoundParameter, typing.Tuple[BoundParameter, typing.Any], None] + + Override this method if some modifications required for parameter value before logging + + .. versionadded:: 3.3.0 + """ return arg def post_process_param(self, arg: BoundParameter, str arg_repr: str) -> str: - """Process parameter for the future logging.""" + """Process parameter for the future logging. + + :param arg: bound parameter + :type arg: BoundParameter + :param arg_repr: repr for value + :type arg_repr: str + :return: processed repr for value + :rtype: str + + Override this method if some modifications required for result of repr() over parameter + + .. versionadded:: 3.3.0 + """ return arg_repr - cdef str _get_func_args_repr(self, sig: inspect.Signature, args: typing.Tuple, kwargs: typing.Dict[str, typing.Any]): - """Internal helper for reducing complexity of decorator code.""" + cdef str _get_func_args_repr(self, sig: inspect.Signature, tuple args, dict kwargs): + """Internal helper for reducing complexity of decorator code. + + :param sig: function signature + :type sig: inspect.Signature + :param args: not keyworded arguments + :type args: typing.Tuple + :param kwargs: keyworded arguments + :type kwargs: typing.Dict[str, typing.Any] + :return: repr over function arguments + :rtype: str + + .. versionchanged:: 3.3.0 Use pre- and post- processing of params during execution + """ if not (self.log_call_args or self.log_call_args_on_exc): return "" @@ -298,7 +378,11 @@ cdef class LogWrap(class_decorator.BaseDecorator): return param_str cdef void _make_done_record(self, str func_name, result: typing.Any): - """Construct success record.""" + """Construct success record. + + :type func_name: str + :type result: typing.Any + """ cdef str msg = "Done: {name!r}".format(name=func_name) if self.log_result_obj: @@ -315,7 +399,12 @@ cdef class LogWrap(class_decorator.BaseDecorator): self._logger.log(level=self.log_level, msg=msg) # type: ignore cdef void _make_calling_record(self, str name, str arguments, str method="Calling"): - """Make log record before execution.""" + """Make log record before execution. + + :type name: str + :type arguments: str + :type method: str + """ self._logger.log( # type: ignore level=self.log_level, msg="{method}: \n{name!r}({arguments})".format( @@ -324,7 +413,11 @@ cdef class LogWrap(class_decorator.BaseDecorator): ) cdef void _make_exc_record(self, str name, str arguments): - """Make log record if exception raised.""" + """Make log record if exception raised. + + :type name: str + :type arguments: str + """ exc_info = sys.exc_info() stack = traceback.extract_stack() tb = traceback.extract_tb(exc_info[2]) @@ -344,7 +437,13 @@ cdef class LogWrap(class_decorator.BaseDecorator): ) def _get_function_wrapper(self, func: typing.Callable) -> typing.Callable: - """Here should be constructed and returned real decorator.""" + """Here should be constructed and returned real decorator. + + :param func: Wrapped function + :type func: typing.Callable + :return: wrapped coroutine or function + :rtype: typing.Callable + """ sig = inspect.signature(self._spec or func) @functools.wraps(func) @@ -401,7 +500,45 @@ def logwrap( bint log_traceback=True, bint log_result_obj=True ) -> typing.Union[LogWrap, typing.Callable]: - """Log function calls and return values.""" + """Log function calls and return values. + + :param func: function to wrap + :type func: typing.Optional[typing.Callable] + :param log: logger object for decorator, by default used 'logwrap' + :type log: logging.Logger + :param log_level: log level for successful calls + :type log_level: int + :param exc_level: log level for exception cases + :type exc_level: int + :param max_indent: maximum indent before classic `repr()` call. + :type max_indent: int + :param spec: callable object used as spec for arguments bind. + This is designed for the special cases only, + when impossible to change signature of target object, + but processed/redirected signature is accessible. + Note: this object should provide fully compatible signature + with decorated function, or arguments bind will be failed! + :type spec: typing.Optional[typing.Callable] + :param blacklisted_names: Blacklisted argument names. Arguments with this names will be skipped in log. + :type blacklisted_names: typing.Optional[typing.Iterable[str]] + :param blacklisted_exceptions: list of exceptions, which should be re-raised without producing log record. + :type blacklisted_exceptions: typing.Optional[typing.Iterable[typing.Type[Exception]]] + :param log_call_args: log call arguments before executing wrapped function. + :type log_call_args: bool + :param log_call_args_on_exc: log call arguments if exception raised. + :type log_call_args_on_exc: bool + :param log_traceback: log traceback on excaption in addition to failure info + :type log_traceback: bool + :param log_result_obj: log result of function call. + :type log_result_obj: bool + :return: built real decorator. + :rtype: _log_wrap_shared.BaseLogWrap + + .. versionchanged:: 3.3.0 Extract func from log and do not use Union. + .. versionchanged:: 3.3.0 Deprecation of *args + .. versionchanged:: 4.0.0 Drop of *args + .. versionchanged:: 5.1.0 log_traceback parameter + """ wrapper = LogWrap( log=log, log_level=log_level, diff --git a/logwrap/repr_utils.py b/logwrap/repr_utils.py index 870401a..a078ee0 100644 --- a/logwrap/repr_utils.py +++ b/logwrap/repr_utils.py @@ -26,6 +26,9 @@ import typing +__all__ = ("PrettyFormat", "PrettyRepr", "PrettyStr", "pretty_repr", "pretty_str") + + def _known_callable(item: typing.Any) -> bool: """Check for possibility to parse callable.""" return isinstance(item, (types.FunctionType, types.MethodType)) @@ -628,6 +631,3 @@ def pretty_str( return PrettyStr(max_indent=max_indent, indent_step=indent_step)( src=src, indent=indent, no_indent_start=no_indent_start ) - - -__all__ = ("PrettyFormat", "PrettyRepr", "PrettyStr", "pretty_repr", "pretty_str") diff --git a/logwrap/repr_utils.pyx b/logwrap/repr_utils.pyx index 1f5c918..d3ff439 100644 --- a/logwrap/repr_utils.pyx +++ b/logwrap/repr_utils.pyx @@ -111,7 +111,12 @@ class ReprParameter: # pylint: disable=no-member def _prepare_repr(func: typing.Union[types.FunctionType, types.MethodType]) -> typing.Iterator[ReprParameter]: - """Get arguments lists with defaults.""" + """Get arguments lists with defaults. + + :param func: Callable object to process + :type func: typing.Union[types.FunctionType, types.MethodType] + :return: repr of callable parameter from signature + :rtype: typing.Iterator[ReprParameter]""" ismethod = isinstance(func, types.MethodType) if not ismethod: real_func = func @@ -140,37 +145,109 @@ cdef class PrettyFormat: """ def __cinit__(self, unsigned int max_indent=20, unsigned int indent_step=4): - """Pretty Formatter.""" + """Pretty Formatter. + + :param max_indent: maximal indent before classic repr() call + :type max_indent: int + :param indent_step: step for the next indentation level + :type indent_step: int + """ self.max_indent = max_indent self.indent_step = indent_step cdef int next_indent(self, unsigned int indent, unsigned int multiplier=1): - """Next indentation value.""" + """Next indentation value. + + :param indent: current indentation value + :type indent: int + :param multiplier: step multiplier + :type multiplier: int + :return: next indentation value + :rtype: int + """ return indent + multiplier * self.indent_step cdef str _repr_callable(self, src: typing.Union[types.FunctionType, types.MethodType], unsigned int indent=0): - """Repr callable object (function or method).""" + """Repr callable object (function or method). + + :param src: Callable to process + :type src: typing.Union[types.FunctionType, types.MethodType] + :param indent: start indentation + :type indent: int + :return: Repr of function or method with signature. + :rtype: str + """ raise NotImplementedError() cdef str _repr_simple(self, src: typing.Any, unsigned int indent=0, bint no_indent_start=False): - """Repr object without iteration.""" + """Repr object without iteration. + + :param src: Source object + :type src: typing.Any + :param indent: start indentation + :type indent: int + :param no_indent_start: ignore indent + :type no_indent_start: bool + :return: simple repr() over object + :rtype: str + """ raise NotImplementedError() def _repr_dict_items(self, dict src, unsigned int indent=0) -> typing.Iterator[str]: # type - """Repr dict items.""" + """Repr dict items. + + :param src: object to process + :type src: typing.Dict + :param indent: start indentation + :type indent: int + :rtype: typing.Iterator[str] + """ raise NotImplementedError() cdef str _repr_iterable_item(self, bint nl, str obj_type, str prefix, unsigned int indent, str result, str suffix): - """Repr iterable item.""" + """Repr iterable item. + + :param nl: newline before item + :type nl: bool + :param obj_type: Object type + :type obj_type: str + :param prefix: prefix + :type prefix: str + :param indent: start indentation + :type indent: int + :param result: result of pre-formatting + :type result: str + :param suffix: suffix + :type suffix: str + :rtype: str + """ raise NotImplementedError() def _repr_iterable_items(self, src: typing.Iterable, unsigned int indent=0) -> typing.Iterator[str]: - """Repr iterable items (not designed for dicts).""" + """Repr iterable items (not designed for dicts). + + :param src: object to process + :type src: typing.Iterable + :param indent: start indentation + :type indent: int + :return: repr of element in iterable item + :rtype: typing.Iterator[str] + """ for elem in src: yield "\n" + self.process_element(src=elem, indent=self.next_indent(indent)) + "," def process_element(self, src: typing.Any, unsigned int indent=0, bint no_indent_start=False) -> str: - """Make human readable representation of object.""" + """Make human readable representation of object. + + :param src: object to process + :type src: typing.Any + :param indent: start indentation + :type indent: int + :param no_indent_start: do not indent open bracket and simple parameters + :type no_indent_start: bool + :return: formatted string + :rtype: str + """ cdef str prefix cdef str suffix cdef str result @@ -206,7 +283,17 @@ cdef class PrettyFormat: ) def __call__(self, src: typing.Any, unsigned int indent=0, bint no_indent_start=False) -> str: - """Make human readable representation of object. The main entry point.""" + """Make human readable representation of object. The main entry point. + + :param src: object to process + :type src: typing.Any + :param indent: start indentation + :type indent: int + :param no_indent_start: do not indent open bracket and simple parameters + :type no_indent_start: bool + :return: formatted string + :rtype: str + """ result = self.process_element(src, indent=indent, no_indent_start=no_indent_start) return result @@ -234,7 +321,17 @@ cdef class PrettyRepr(PrettyFormat): return "{spc:<{indent}}{prefix}'''{string}'''".format(spc="", indent=indent, prefix=prefix, string=val) cdef str _repr_simple(self, src: typing.Any, unsigned int indent=0, bint no_indent_start=False): - """Repr object without iteration.""" + """Repr object without iteration. + + :param src: Source object + :type src: typing.Any + :param indent: start indentation + :type indent: int + :param no_indent_start: ignore indent + :type no_indent_start: bool + :return: simple repr() over object, except strings (add prefix) and set (uniform py2/py3) + :rtype: str + """ indent = 0 if no_indent_start else indent if isinstance(src, set): return "{spc:<{indent}}{val}".format(spc="", indent=indent, val="set(" + " ,".join(map(repr, src)) + ")") @@ -243,7 +340,15 @@ cdef class PrettyRepr(PrettyFormat): return "{spc:<{indent}}{val!r}".format(spc="", indent=indent, val=src) def _repr_dict_items(self, dict src, unsigned int indent=0) -> typing.Iterator[str]: - """Repr dict items.""" + """Repr dict items. + + :param src: object to process + :type src: dict + :param indent: start indentation + :type indent: int + :return: repr of key/value pair from dict + :rtype: typing.Iterator[str] + """ cdef unsigned int max_len = max((len(repr(key)) for key in src)) if src else 0 for key, val in src.items(): @@ -256,7 +361,15 @@ cdef class PrettyRepr(PrettyFormat): ) cdef str _repr_callable(self, src: typing.Union[types.FunctionType, types.MethodType], unsigned int indent=0): - """Repr callable object (function or method).""" + """Repr callable object (function or method). + + :param src: Callable to process + :type src: typing.Union[types.FunctionType, types.MethodType] + :param indent: start indentation + :type indent: int + :return: Repr of function or method with signature. + :rtype: str + """ cdef str param_str = "" cdef str annotation @@ -284,7 +397,23 @@ cdef class PrettyRepr(PrettyFormat): ) cdef str _repr_iterable_item(self, bint nl, str obj_type, str prefix, unsigned int indent, str result, str suffix): - """Repr iterable item.""" + """Repr iterable item. + + :param nl: newline before item + :type nl: bool + :param obj_type: Object type + :type obj_type: str + :param prefix: prefix + :type prefix: str + :param indent: start indentation + :type indent: int + :param result: result of pre-formatting + :type result: str + :param suffix: suffix + :type suffix: str + :return: formatted repr of "result" with prefix and suffix to explain type. + :rtype: str + """ return ( "{nl}" "{spc:<{indent}}{obj_type:}({prefix}{result}\n" @@ -301,7 +430,10 @@ cdef class PrettyRepr(PrettyFormat): cdef class PrettyStr(PrettyFormat): - """Pretty str.""" + """Pretty str. + + Designed for usage as __str__ replacement on complex objects + """ def __cinit__(self, unsigned int max_indent=20, unsigned int indent_step=4): self._magic_method_name = "__pretty_str__" @@ -313,7 +445,17 @@ cdef class PrettyStr(PrettyFormat): return "{spc:<{indent}}{string}".format(spc="", indent=indent, string=val) cdef str _repr_simple(self, src: typing.Any, unsigned int indent=0, bint no_indent_start=False): - """Repr object without iteration.""" + """Repr object without iteration. + + :param src: Source object + :type src: typing.Any + :param indent: start indentation + :type indent: int + :param no_indent_start: ignore indent + :type no_indent_start: bool + :return: simple repr() over object, except strings (decode) and set (uniform py2/py3) + :rtype: str + """ indent = 0 if no_indent_start else indent if isinstance(src, set): return "{spc:<{indent}}{val}".format(spc="", indent=indent, val="set(" + " ,".join(map(str, src)) + ")") @@ -322,7 +464,15 @@ cdef class PrettyStr(PrettyFormat): return "{spc:<{indent}}{val!s}".format(spc="", indent=indent, val=src) def _repr_dict_items(self, dict src, unsigned int indent=0) -> typing.Iterator[str]: - """Repr dict items.""" + """Repr dict items. + + :param src: object to process + :type src: dict + :param indent: start indentation + :type indent: int + :return: repr of key/value pair from dict + :rtype: typing.Iterator[str] + """ cdef unsigned int max_len = max((len(str(key)) for key in src)) if src else 0 for key, val in src.items(): yield "\n{spc:<{indent}}{key!s:{size}}: {val},".format( @@ -334,7 +484,15 @@ cdef class PrettyStr(PrettyFormat): ) cdef str _repr_callable(self, src: typing.Union[types.FunctionType, types.MethodType], unsigned int indent=0): - """Repr callable object (function or method).""" + """Repr callable object (function or method). + + :param src: Callable to process + :type src: typing.Union[types.FunctionType, types.MethodType] + :param indent: start indentation + :type indent: int + :return: Repr of function or method with signature. + :rtype: str + """ cdef str param_str = "" cdef str annotation @@ -362,7 +520,23 @@ cdef class PrettyStr(PrettyFormat): ) cdef str _repr_iterable_item(self, bint nl, str obj_type, str prefix, unsigned int indent, str result, str suffix): - """Repr iterable item.""" + """Repr iterable item. + + :param nl: newline before item + :type nl: bool + :param obj_type: Object type + :type obj_type: str + :param prefix: prefix + :type prefix: str + :param indent: start indentation + :type indent: int + :param result: result of pre-formatting + :type result: str + :param suffix: suffix + :type suffix: str + :return: formatted repr of "result" with prefix and suffix to explain type. + :rtype: str + """ return ( "{nl}" "{spc:<{indent}}{prefix}{result}\n" @@ -379,7 +553,21 @@ def pretty_repr( unsigned int max_indent=20, unsigned int indent_step=4 ) -> str: - """Make human readable repr of object.""" + """Make human readable repr of object. + + :param src: object to process + :type src: typing.Any + :param indent: start indentation, all next levels is +indent_step + :type indent: int + :param no_indent_start: do not indent open bracket and simple parameters + :type no_indent_start: bool + :param max_indent: maximal indent before classic repr() call + :type max_indent: int + :param indent_step: step for the next indentation level + :type indent_step: int + :return: formatted string + :rtype: str + """ return PrettyRepr(max_indent=max_indent, indent_step=indent_step)( src=src, indent=indent, no_indent_start=no_indent_start ) @@ -392,7 +580,20 @@ def pretty_str( unsigned int max_indent=20, unsigned int indent_step=4 ) -> str: - """Make human readable str of object.""" + """Make human readable str of object. + + :param src: object to process + :type src: typing.Any + :param indent: start indentation, all next levels is +indent_step + :type indent: int + :param no_indent_start: do not indent open bracket and simple parameters + :type no_indent_start: bool + :param max_indent: maximal indent before classic repr() call + :type max_indent: int + :param indent_step: step for the next indentation level + :type indent_step: int + :return: formatted string + """ return PrettyStr(max_indent=max_indent, indent_step=indent_step)( src=src, indent=indent, no_indent_start=no_indent_start )