Source code for configflow.misc.string

"""Module for the string helper functions and primitive data types."""

from __future__ import annotations

import warnings

from ast import literal_eval
from typing import Any
from typing import Optional

import apm


# WPS600 - inheritance from the str is the only way to implement correct
# error message with all str functionality
[docs]class ErrorMessage(str): # noqa: WPS600 """Implementation of the error message. Notes ----- By default, error messages in the exceptions don't support line breaks or any formatting, this decorator is solving that problem. References ---------- 1. `New line on error message in KeyError - Python 3.3 <https://stackoverflow.com/questions/ 46892261/new-line-on-error-message-in-keyerror-python-3-3>`_ """
[docs] def __repr__(self) -> str: r"""Get object representation. Examples -------- >>> msg = ErrorMessage("\nInvalid argument: 'db'.\nExpected arguments: ['db2', 'port'].") >>> repr(msg) \nInvalid argument: 'db'.\nExpected arguments: ['db2', 'port']. >>> raise ValueError(msg) Traceback (most recent call last): ... ValueError: Invalid argument: 'db'. Expected arguments: ['db2', 'port']. """ return self.__str__()
# WPS110 - in this context value is an abstract name
[docs]def parse(value: str) -> Optional[Any]: # noqa: WPS110 """Parse a string value to the appropriate Python object. Notes ----- If a value is a sequence ``list | tuple | set`` then ``parse`` function will be applied to each element of a sequence. Warnings -------- Currently ``parse`` function supports only primitive data types ``int | str | float`` and sequences ``list | tuple | set``. Sequences such as ``dict`` will be returned as they are without parsing their inner values. Examples -------- >>> parse("1.2") 1.2 >>> parse("(1, 2, '3')") (1, 2, 3) >>> parse("['85', '0.23', 'cleffa', ['10', ['0.123'], 'blipbug']]") [85, 0.23, 'cleffa', [10, [0.123], 'blipbug']] """ try: literal = literal_eval(value) except ValueError: original_type = type(value) return ( apm.case(value) .of(apm.InstanceOf(list, set, tuple), lambda _: original_type(map(parse, value))) .otherwise(lambda _: value) ) except SyntaxError as exception: warnings.warn( message="Error during object parsing {0!r}. Suppressed exception {1!s}.".format( value, exception, ), category=UserWarning, ) return None original_type = type(literal) return ( apm.case(literal) .of(apm.InstanceOf(float), lambda _: int(literal) if literal.is_integer() else literal) .of(apm.InstanceOf(list, set, tuple), lambda _: original_type(map(parse, literal))) .otherwise(lambda _: literal) )