Skip to content

Commit

Permalink
Add maybe_apply function
Browse files Browse the repository at this point in the history
  • Loading branch information
DeviousStoat committed Feb 20, 2024
1 parent ef48d55 commit 8413197
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/pydash/__init__.py
Expand Up @@ -190,6 +190,7 @@
map_keys,
map_values,
map_values_deep,
maybe_apply,
merge,
merge_with,
omit,
Expand Down Expand Up @@ -566,6 +567,7 @@
"map_keys",
"map_values",
"map_values_deep",
"maybe_apply",
"merge",
"merge_with",
"omit",
Expand Down
5 changes: 5 additions & 0 deletions src/pydash/chaining/all_funcs.pyi
Expand Up @@ -2545,6 +2545,11 @@ class AllFuncs:
) -> "Chain[t.Any]":
return self._wrap(pyd.map_values_deep)(iteratee, property_path)

def maybe_apply(
self: "Chain[t.Optional[T]]", func: t.Callable[[T], T2]
) -> "Chain[t.Optional[T2]]":
return self._wrap(pyd.maybe_apply)(func)

@t.overload
def merge(
self: "Chain[t.Mapping[T, T2]]", *sources: t.Mapping[T3, T4]
Expand Down
24 changes: 24 additions & 0 deletions src/pydash/objects.py
Expand Up @@ -43,6 +43,7 @@
"map_keys",
"map_values",
"map_values_deep",
"maybe_apply",
"merge",
"merge_with",
"omit",
Expand Down Expand Up @@ -1320,6 +1321,29 @@ def deep_iteratee(value, key):
return callit(iteratee, obj, properties)


def maybe_apply(obj: t.Optional[T], func: t.Callable[[T], T2]) -> t.Optional[T2]:
"""
Apply `func` to `obj` if `obj` is not ``None``.
Args:
obj: Object to apply `func` to.
func: Function to apply to `obj`.
Returns:
Result of applying `func` to `obj` or ``None``.
Example:
>>> maybe_apply(2, lambda x: x * 2)
4
>>> maybe_apply(None, lambda x: x * 2) is None
True
.. versionadded:: 8.0.0
"""
return func(obj) if obj is not None else None


@t.overload
def merge(
obj: t.Mapping[T, T2], *sources: t.Mapping[T3, T4]
Expand Down
7 changes: 7 additions & 0 deletions tests/pytest_mypy_testing/test_objects.py
Expand Up @@ -345,3 +345,10 @@ def test_mypy_values() -> None:
reveal_type(_.values({'a': 1, 'b': 2, 'c': 3})) # R: builtins.list[builtins.int]
reveal_type(_.values([2, 4, 6, 8])) # R: builtins.list[builtins.int]
reveal_type(_.values(MyClass())) # R: builtins.list[Any]


@pytest.mark.mypy_testing
def test_mypy_maybe_apply() -> None:
reveal_type(_.maybe_apply(1, lambda x: x + 1)) # R: Union[builtins.int, None]
reveal_type(_.maybe_apply(None, lambda x: x + 1)) # R: Union[builtins.int, None]
reveal_type(_.maybe_apply("hello", lambda x: x.upper())) # R: Union[builtins.str, None]
5 changes: 5 additions & 0 deletions tests/test_objects.py
Expand Up @@ -944,3 +944,8 @@ def test_unset(obj, path, expected, new_obj):
@parametrize("case,expected", [({"a": 1, "b": 2, "c": 3}, [1, 2, 3]), ([1, 2, 3], [1, 2, 3])])
def test_values(case, expected):
assert set(_.values(case)) == set(expected)


@parametrize("case,expected", [((5, lambda x: x * 2), 10), ((None, lambda x: x * 2), None)])
def test_maybe_apply(case, expected):
assert _.maybe_apply(*case) == expected

0 comments on commit 8413197

Please sign in to comment.