Example #1
0
def test_rescue_with_result():
    """Ensures that functions can be composed and return type is correct."""
    rescued = rescue(_result_function)

    assert rescued(Success(1)) == Success(1)
    assert rescued(Failure(1)) == Success(2)
    assert rescued(Failure(0)) == Failure('nope')
Example #2
0
    def __call__(
        self,
        value_to_cast: MapValue,
        original_format: str,
    ) -> ResultE[MapValue]:
        r"""
        purpose: Convert string date into ISO format date.

        :input value_to_cast: the string to be converted to a date
        :input original_format: a string describing the format the data string
                             is before convertion.
        :raises ValueError:  when not able to convert or value_to_cast
                             does not match original_format.
        regex_tips  ^ = start of string
                    $ = end of string
                    [^[0-9]] = matches anything not [0-9]
                    [^\d] = matches anything not digits
                    \d = matches digits
                    {n} = matches previous match n amount of times
                    () = grouper, groups up stuff for use in replace.
        """
        date_value: str = str(value_to_cast)
        return flow(
            date_value,
            self._value_is_iso,
            rescue(  # type: ignore
                lambda _: self._cast_with_millennia(
                    date_value,
                    original_format=original_format,
                ),
            ),
            rescue(  # type: ignore
                lambda _: self._cast_with_no_millennia(
                    date_value,
                    original_format=original_format,
                ),
            ),
            bind(self._validate_date),
            alt(  # type: ignore
                lambda failure: ValueError(
                    self._error_message.format(
                        value=date_value,
                        failure=failure,
                    ),
                ),
            ),
        )
Example #3
0
def test_rescue_with_context_result():
    """Ensures that functions can be composed and return type is correct."""
    rescued = rescue(_context_result_function)

    assert rescued(RequiresContextResult.from_value(1), )(1) == Success(1)
    assert rescued(RequiresContextResult.from_failure(1), )(1) == Success(2)
    assert rescued(
        RequiresContextResult.from_failure(0), )(1) == Failure('nope')
Example #4
0
def handle_attribute(
    collection: Union[Dict[str, Any], List[Any]],
    cfg: dict,
) -> ResultE[MapValue]:
    """Handle one attribute with mappings, ifs, casting and default value.

    :param collection: The collection of data to find data in
    :type collection: Union[Dict[str, Any], List[Any]]

    :param configuration: :term:`configuration` data to use when mapping
    :type configuration: Dict[str, Any]

    :return: Success/Failure containers
    :rtype: MapValue

    configuration expected to look like this:

    .. code-block:: json

        {
            "mappings": [],  # array of mapping objects
            "separator": None,
            "if_statements": [],  # array of if statement objects
            "casting": {}  # casting object, for casting types
            "default": "default value"
        }

    flow description:

    Map all objects in cfg[MAPPINGS] ->
    Apply separator to values if there are more than 1
    Failure -> fix to Success(None)
    Apply if statements
    Success -> Cast Value
    Failure -> apply default value

    Return Result
    """
    mapped_values = [
        mapped.unwrap() for mapped in [
            handle_mapping(collection, mapping)
            for mapping in cfg.get(MAPPINGS, [])
        ] if is_successful(mapped)
    ]

    # partially declare if statement and casting functions
    ifs = partial(apply_if_statements, if_objects=cfg.get(IF_STATEMENTS, []))
    cast = partial(apply_casting, casting=cfg.get(CASTING, {}))

    return flow(
        apply_separator(mapped_values, separator=cfg.get(SEPARATOR, '')),
        fix(lambda _: None),  # type: ignore
        bind(ifs),
        bind(cast),
        rescue(lambda _: apply_default(default=cfg.get(DEFAULT)), ),
    )
Example #5
0
def handle_mapping(
    collection: Union[Dict[str, Any], List[Any]],
    cfg: Dict[str, Any],
) -> ResultE[MapValue]:
    """Find data in path and apply if statements or default value.

    .. versionadded:: 0.0.1

    :param configuration: :term:`configuration` data to use when mapping
    :type configuration: Dict[str, Any]

    :param collection: The collection of data to find data in
    :type collection: Union[Dict[str, Any], List[Any]]

    :return: Success/Failure containers
    :rtype: GoResult

    configuration expected to look like this:

    .. code-block:: json
        {
            "path": [],
            "if_statementss": [{}, {}],
            "default": 'val'
        }

    Flow description:

    find data from path or None ->
    apply if statements ->
    return default value if Failure else mapped value
    """
    return flow(
        collection,
        partial(fetch_data_by_keys, path=cfg.get(PATH, [])),
        fix(lambda _: None),  # type: ignore
        bind(partial(
            apply_regexp,
            regexp=cfg.get(REGEXP, {}),
        ), ),
        fix(lambda _: None),  # type: ignore
        map_(partial(
            apply_slicing,
            slicing=cfg.get(SLICING, {}),
        )),
        bind(
            partial(
                apply_if_statements,
                if_objects=cfg.get(IF_STATEMENTS, []),
            )),
        rescue(  # type: ignore
            lambda _: apply_default(cfg.get(DEFAULT)), ),
    )
Example #6
0
def handle_data_fetcher(
    collection: Union[Dict[str, Any], List[Any]],
    cfg: DataFetcher,
) -> ResultE[AnyType]:
    """Find a data at path or produce a value.

    return value can be:
    - value found at path
    - value found but sliced
    - value found applied to regular expression
    - conditional value depending on if statements
    - default value if all the above still produces `None`

    Flow description:

    find data from path or None ->
    apply regular expression ->
    apply slicing ->
    apply if statements ->
    return default value if Failure else mapped value
    """
    return flow(
        collection,
        partial(fetch_data_by_keys, path=cfg.path),
        fix(lambda _: None),  # type: ignore
        bind(partial(
            apply_regex,
            regex=cfg.regex,
        ), ),
        fix(lambda _: None),  # type: ignore
        map_(partial(
            apply_slicing,
            slicing=cfg.slicing,
        )),
        bind(partial(
            apply_if_statements,
            statements=cfg.if_statements,
        )),
        rescue(  # type: ignore
            lambda _: apply_default(cfg.default), ),
    )
Example #7
0
def handle_attribute(
    collection: Union[Dict[str, Any], List[Any]],
    cfg: Attribute,
) -> ResultE[AnyType]:
    """Handle one attribute with data fetchers, ifs, casting and default value.

    flow description:

    Fetch once for all data in Attribute.data_fetchers ->
    Apply separator to values if there are more than 1
    Failure -> fix to Success(None)
    Apply if statements
    Success -> Cast Value
    Failure -> apply default value

    Return Result
    """
    fetched_values = [
        fetched.unwrap() for fetched in  # noqa: WPS361
        [
            handle_data_fetcher(collection, data_fetcher)
            for data_fetcher in cfg.data_fetchers
        ] if is_successful(fetched)
    ]

    # partially declare if statement and casting functions
    ifs = partial(apply_if_statements, statements=cfg.if_statements)

    cast = safe(lambda the_value: the_value)
    if cfg.casting:
        cast = partial(apply_casting, casting=cfg.casting)

    return flow(
        apply_separator(fetched_values, separator=cfg.separator),
        fix(lambda _: None),  # type: ignore
        bind(ifs),
        bind(cast),
        rescue(lambda _: apply_default(default=cfg.default), ),
    )