aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/pydash/objects.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/pydash/objects.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-4a52a71956a8d46fcb7294ac71734504bb09bcc2.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/pydash/objects.py')
-rw-r--r--.venv/lib/python3.12/site-packages/pydash/objects.py2633
1 files changed, 2633 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pydash/objects.py b/.venv/lib/python3.12/site-packages/pydash/objects.py
new file mode 100644
index 00000000..442cf722
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pydash/objects.py
@@ -0,0 +1,2633 @@
+"""
+Functions that operate on lists, dicts, and other objects.
+
+.. versionadded:: 1.0.0
+"""
+
+from __future__ import annotations
+
+import copy
+from functools import partial
+import math
+import re
+import typing as t
+
+import pydash as pyd
+
+from .helpers import UNSET, Unset, base_get, base_set, callit, getargcount, iterator, iteriteratee
+from .types import IterateeObjT, PathT
+from .utilities import PathToken, to_path, to_path_tokens
+
+
+if t.TYPE_CHECKING:
+ from _typeshed import SupportsRichComparisonT # pragma: no cover
+
+__all__ = (
+ "apply",
+ "apply_catch",
+ "apply_if",
+ "apply_if_not_none",
+ "assign",
+ "assign_with",
+ "callables",
+ "clone",
+ "clone_deep",
+ "clone_deep_with",
+ "clone_with",
+ "defaults",
+ "defaults_deep",
+ "find_key",
+ "find_last_key",
+ "for_in",
+ "for_in_right",
+ "get",
+ "has",
+ "invert",
+ "invert_by",
+ "invoke",
+ "keys",
+ "map_keys",
+ "map_values",
+ "map_values_deep",
+ "merge",
+ "merge_with",
+ "omit",
+ "omit_by",
+ "parse_int",
+ "pick",
+ "pick_by",
+ "rename_keys",
+ "set_",
+ "set_with",
+ "to_boolean",
+ "to_dict",
+ "to_integer",
+ "to_list",
+ "to_number",
+ "to_pairs",
+ "to_string",
+ "transform",
+ "unset",
+ "update",
+ "update_with",
+ "values",
+)
+
+T = t.TypeVar("T")
+T2 = t.TypeVar("T2")
+T3 = t.TypeVar("T3")
+T4 = t.TypeVar("T4")
+T5 = t.TypeVar("T5")
+
+
+@t.overload
+def assign(
+ obj: t.Mapping[T, T2], *sources: t.Mapping[T3, T4]
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T4]]: ...
+
+
+@t.overload
+def assign(
+ obj: t.Union[t.Tuple[T, ...], t.List[T]], *sources: t.Mapping[int, T2]
+) -> t.List[t.Union[T, T2]]: ...
+
+
+def assign(obj, *sources) -> t.Union[t.List[t.Any], t.Dict[t.Any, t.Any]]:
+ """
+ Assigns properties of source object(s) to the destination object.
+
+ Args:
+ obj: Destination object whose properties will be modified.
+ sources: Source objects to assign to `obj`.
+
+ Returns:
+ Modified `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> obj = {}
+ >>> obj2 = assign(obj, {"a": 1}, {"b": 2}, {"c": 3})
+ >>> obj == {"a": 1, "b": 2, "c": 3}
+ True
+ >>> obj is obj2
+ True
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 2.3.2
+ Apply :func:`clone_deep` to each `source` before assigning to `obj`.
+
+ .. versionchanged:: 3.0.0
+ Allow iteratees to accept partial arguments.
+
+ .. versionchanged:: 3.4.4
+ Shallow copy each `source` instead of deep copying.
+
+ .. versionchanged:: 4.0.0
+
+ - Moved `iteratee` argument to :func:`assign_with`.
+ - Removed alias ``extend``.
+ """
+ return assign_with(obj, *sources) # type: ignore
+
+
+@t.overload
+def assign_with(
+ obj: t.Mapping[T, T2],
+ *sources: t.Mapping[T3, t.Any],
+ customizer: t.Callable[[t.Union[T2, None]], T5],
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T5]]: ...
+
+
+@t.overload
+def assign_with(
+ obj: t.Mapping[T, T2],
+ *sources: t.Mapping[T3, T4],
+ customizer: t.Callable[[t.Union[T2, None], T4], T5],
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T5]]: ...
+
+
+@t.overload
+def assign_with(
+ obj: t.Mapping[T, T2],
+ *sources: t.Mapping[T3, T4],
+ customizer: t.Callable[[t.Union[T2, None], T4, T3], T5],
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T5]]: ...
+
+
+@t.overload
+def assign_with(
+ obj: t.Mapping[T, T2],
+ *sources: t.Mapping[T3, T4],
+ customizer: t.Callable[[t.Union[T2, None], T4, T3, t.Dict[T, T2]], T5],
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T5]]: ...
+
+
+@t.overload
+def assign_with(
+ obj: t.Mapping[T, T2],
+ *sources: t.Mapping[T3, T4],
+ customizer: t.Callable[[t.Union[T2, None], T4, T3, t.Dict[T, T2], t.Dict[T3, T4]], T5],
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T5]]: ...
+
+
+@t.overload
+def assign_with(
+ obj: t.Mapping[T, T2], *sources: t.Mapping[T3, T4], customizer: None = None
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T4]]: ...
+
+
+def assign_with(obj, *sources, customizer=None):
+ """
+ This method is like :func:`assign` except that it accepts customizer which is invoked to produce
+ the assigned values. If customizer returns ``None``, assignment is handled by the method
+ instead. The customizer is invoked with five arguments: ``(obj_value, src_value, key, obj,
+ source)``.
+
+ Args:
+ obj: Destination object whose properties will be modified.
+ sources: Source objects to assign to `obj`.
+
+ Keyword Args:
+ customizer: Customizer applied per iteration.
+
+ Returns:
+ Modified `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> customizer = lambda o, s: s if o is None else o
+ >>> results = assign_with({"a": 1}, {"b": 2}, {"a": 3}, customizer)
+ >>> results == {"a": 1, "b": 2}
+ True
+
+ .. versionadded:: 4.0.0
+ """
+ sources = list(sources)
+
+ if customizer is None and callable(sources[-1]):
+ customizer = sources.pop()
+
+ if customizer is not None:
+ argcount = getargcount(customizer, maxargs=5)
+ else:
+ argcount = None
+
+ for source in sources:
+ source = source.copy()
+
+ for key, value in source.items():
+ if customizer:
+ val = callit(customizer, obj.get(key), value, key, obj, source, argcount=argcount)
+ if val is not None:
+ value = val
+
+ obj[key] = value
+
+ return obj
+
+
+@t.overload
+def callables(
+ obj: t.Mapping["SupportsRichComparisonT", t.Any],
+) -> t.List["SupportsRichComparisonT"]: ...
+
+
+@t.overload
+def callables(obj: t.Iterable[T]) -> t.List[T]: ...
+
+
+def callables(obj):
+ """
+ Creates a sorted list of keys of an object that are callable.
+
+ Args:
+ obj: Object to inspect.
+
+ Returns:
+ All keys whose values are callable.
+
+ Example:
+
+ >>> callables({"a": 1, "b": lambda: 2, "c": lambda: 3})
+ ['b', 'c']
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 2.0.0
+ Renamed ``functions`` to ``callables``.
+
+ .. versionchanged:: 4.0.0
+ Removed alias ``methods``.
+ """
+ return sorted(key for key, value in iterator(obj) if callable(value))
+
+
+def clone(value: T) -> T:
+ """
+ Creates a clone of `value`.
+
+ Args:
+ value: Object to clone.
+
+ Example:
+
+ >>> x = {"a": 1, "b": 2, "c": {"d": 3}}
+ >>> y = clone(x)
+ >>> y == y
+ True
+ >>> x is y
+ False
+ >>> x["c"] is y["c"]
+ True
+
+ Returns:
+ Cloned object.
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.0.0
+ Moved 'iteratee' parameter to :func:`clone_with`.
+ """
+ return base_clone(value)
+
+
+@t.overload
+def clone_with(
+ value: t.Mapping[T, T2], customizer: t.Callable[[T2, T, t.Mapping[T, T2]], T3]
+) -> t.Dict[T, t.Union[T2, T3]]: ...
+
+
+@t.overload
+def clone_with(
+ value: t.Mapping[T, T2], customizer: t.Callable[[T2, T], T3]
+) -> t.Dict[T, t.Union[T2, T3]]: ...
+
+
+@t.overload
+def clone_with(
+ value: t.Mapping[T, T2], customizer: t.Callable[[T2], T3]
+) -> t.Dict[T, t.Union[T2, T3]]: ...
+
+
+@t.overload
+def clone_with(
+ value: t.List[T], customizer: t.Callable[[T, int, t.List[T]], T2]
+) -> t.List[t.Union[T, T2]]: ...
+
+
+@t.overload
+def clone_with(
+ value: t.List[T], customizer: t.Callable[[T, int], T2]
+) -> t.List[t.Union[T, T2]]: ...
+
+
+@t.overload
+def clone_with(value: t.List[T], customizer: t.Callable[[T], T2]) -> t.List[t.Union[T, T2]]: ...
+
+
+@t.overload
+def clone_with(value: T, customizer: None = None) -> T: ...
+
+
+@t.overload
+def clone_with(value: t.Any, customizer: t.Callable[..., t.Any]) -> t.Any: ...
+
+
+def clone_with(value, customizer=None):
+ """
+ This method is like :func:`clone` except that it accepts customizer which is invoked to produce
+ the cloned value. If customizer returns ``None``, cloning is handled by the method instead. The
+ customizer is invoked with up to three arguments: ``(value, index|key, object)``.
+
+ Args:
+ value: Object to clone.
+ customizer: Function to customize cloning.
+
+ Returns:
+ Cloned object.
+
+ Example:
+
+ >>> x = {"a": 1, "b": 2, "c": {"d": 3}}
+ >>> cbk = lambda v, k: v + 2 if isinstance(v, int) and k else None
+ >>> y = clone_with(x, cbk)
+ >>> y == {"a": 3, "b": 4, "c": {"d": 3}}
+ True
+ """
+ return base_clone(value, customizer=customizer)
+
+
+def clone_deep(value: T) -> T:
+ """
+ Creates a deep clone of `value`. If an iteratee is provided it will be executed to produce the
+ cloned values.
+
+ Args:
+ value: Object to clone.
+
+ Returns:
+ Cloned object.
+
+ Example:
+
+ >>> x = {"a": 1, "b": 2, "c": {"d": 3}}
+ >>> y = clone_deep(x)
+ >>> y == y
+ True
+ >>> x is y
+ False
+ >>> x["c"] is y["c"]
+ False
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.0.0
+ Moved 'iteratee' parameter to :func:`clone_deep_with`.
+ """
+ return base_clone(value, is_deep=True)
+
+
+@t.overload
+def clone_deep_with(
+ value: t.Mapping[T, T2], customizer: t.Callable[[T2, T, t.Mapping[T, T2]], T3]
+) -> t.Dict[T, t.Union[T2, T3]]: ...
+
+
+@t.overload
+def clone_deep_with(
+ value: t.Mapping[T, T2], customizer: t.Callable[[T2, T], T3]
+) -> t.Dict[T, t.Union[T2, T3]]: ...
+
+
+@t.overload
+def clone_deep_with(
+ value: t.Mapping[T, T2], customizer: t.Callable[[T2], T3]
+) -> t.Dict[T, t.Union[T2, T3]]: ...
+
+
+@t.overload
+def clone_deep_with(
+ value: t.List[T], customizer: t.Callable[[T, int, t.List[T]], T2]
+) -> t.List[t.Union[T, T2]]: ...
+
+
+@t.overload
+def clone_deep_with(
+ value: t.List[T], customizer: t.Callable[[T, int], T2]
+) -> t.List[t.Union[T, T2]]: ...
+
+
+@t.overload
+def clone_deep_with(
+ value: t.List[T], customizer: t.Callable[[T], T2]
+) -> t.List[t.Union[T, T2]]: ...
+
+
+@t.overload
+def clone_deep_with(value: T, customizer: None = None) -> T: ...
+
+
+@t.overload
+def clone_deep_with(value: t.Any, customizer: t.Callable[..., t.Any]) -> t.Any: ...
+
+
+def clone_deep_with(value, customizer=None):
+ """
+ This method is like :func:`clone_with` except that it recursively clones `value`.
+
+ Args:
+ value: Object to clone.
+ customizer: Function to customize cloning.
+
+ Returns:
+ Cloned object.
+ """
+ return base_clone(value, is_deep=True, customizer=customizer)
+
+
+def defaults(
+ obj: t.Dict[T, T2], *sources: t.Dict[T3, T4]
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T4]]:
+ """
+ Assigns properties of source object(s) to the destination object for all destination properties
+ that resolve to undefined.
+
+ Args:
+ obj: Destination object whose properties will be modified.
+ sources: Source objects to assign to `obj`.
+
+ Returns:
+ Modified `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> obj = {"a": 1}
+ >>> obj2 = defaults(obj, {"b": 2}, {"c": 3}, {"a": 4})
+ >>> obj is obj2
+ True
+ >>> obj == {"a": 1, "b": 2, "c": 3}
+ True
+
+ .. versionadded:: 1.0.0
+ """
+ for source in sources:
+ for key, value in source.items():
+ obj.setdefault(key, value) # type: ignore
+
+ return obj # type: ignore
+
+
+def defaults_deep(
+ obj: t.Dict[T, T2], *sources: t.Dict[T3, T4]
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T4]]:
+ """
+ This method is like :func:`defaults` except that it recursively assigns default properties.
+
+ Args:
+ obj: Destination object whose properties will be modified.
+ sources: Source objects to assign to `obj`.
+
+ Returns:
+ Modified `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> obj = {"a": {"b": 1}}
+ >>> obj2 = defaults_deep(obj, {"a": {"b": 2, "c": 3}})
+ >>> obj is obj2
+ True
+ >>> obj == {"a": {"b": 1, "c": 3}}
+ True
+
+ .. versionadded:: 3.3.0
+ """
+
+ def setter(obj, key, value):
+ if hasattr(obj, "setdefault"):
+ obj.setdefault(key, value)
+
+ return merge_with(obj, *sources, _setter=setter)
+
+
+@t.overload
+def find_key(
+ obj: t.Mapping[T, T2], predicate: t.Callable[[T2, T, t.Dict[T, T2]], t.Any]
+) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_key(obj: t.Mapping[T, T2], predicate: t.Callable[[T2, T], t.Any]) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_key(obj: t.Mapping[T, T2], predicate: t.Callable[[T2], t.Any]) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_key(obj: t.Mapping[T, t.Any], predicate: None = None) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_key(
+ collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], t.Any]
+) -> t.Union[int, None]: ...
+
+
+@t.overload
+def find_key(
+ collection: t.Iterable[T], iteratee: t.Callable[[T, int], t.Any]
+) -> t.Union[int, None]: ...
+
+
+@t.overload
+def find_key(collection: t.Iterable[T], iteratee: t.Callable[[T], t.Any]) -> t.Union[int, None]: ...
+
+
+@t.overload
+def find_key(collection: t.Iterable[t.Any], iteratee: None = None) -> t.Union[int, None]: ...
+
+
+def find_key(obj, predicate=None):
+ """
+ This method is like :func:`pydash.arrays.find_index` except that it returns the key of the first
+ element that passes the predicate check, instead of the element itself.
+
+ Args:
+ obj: Object to search.
+ predicate: Predicate applied per iteration.
+
+ Returns:
+ Found key or ``None``.
+
+ Example:
+
+ >>> find_key({"a": 1, "b": 2, "c": 3}, lambda x: x == 1)
+ 'a'
+ >>> find_key([1, 2, 3, 4], lambda x: x == 1)
+ 0
+
+ .. versionadded:: 1.0.0
+ """
+ for result, _, key, _ in iteriteratee(obj, predicate):
+ if result:
+ return key
+
+
+@t.overload
+def find_last_key(
+ obj: t.Mapping[T, T2], predicate: t.Callable[[T2, T, t.Dict[T, T2]], t.Any]
+) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_last_key(
+ obj: t.Mapping[T, T2], predicate: t.Callable[[T2, T], t.Any]
+) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_last_key(
+ obj: t.Mapping[T, T2], predicate: t.Callable[[T2], t.Any]
+) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_last_key(obj: t.Mapping[T, t.Any], predicate: None = None) -> t.Union[T, None]: ...
+
+
+@t.overload
+def find_last_key(
+ collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], t.Any]
+) -> t.Union[int, None]: ...
+
+
+@t.overload
+def find_last_key(
+ collection: t.Iterable[T], iteratee: t.Callable[[T, int], t.Any]
+) -> t.Union[int, None]: ...
+
+
+@t.overload
+def find_last_key(
+ collection: t.Iterable[T], iteratee: t.Callable[[T], t.Any]
+) -> t.Union[int, None]: ...
+
+
+@t.overload
+def find_last_key(collection: t.Iterable[t.Any], iteratee: None = None) -> t.Union[int, None]: ...
+
+
+def find_last_key(obj, predicate=None):
+ """
+ This method is like :func:`find_key` except that it iterates over elements of a collection in
+ the opposite order.
+
+ Args:
+ obj: Object to search.
+ predicate: Predicate applied per iteration.
+
+ Returns:
+ Found key or ``None``.
+
+ Example:
+
+ >>> find_last_key({"a": 1, "b": 2, "c": 3}, lambda x: x == 1)
+ 'a'
+ >>> find_last_key([1, 2, 3, 1], lambda x: x == 1)
+ 3
+
+ .. versionchanged:: 4.0.0
+ Made into its own function (instead of an alias of ``find_key``) with
+ proper reverse find implementation.
+ """
+ reversed_obj = reversed(list(iteriteratee(obj, predicate)))
+ for result, _, key, _ in reversed_obj:
+ if result:
+ return key
+
+
+@t.overload
+def for_in(
+ obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], t.Any]
+) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in(obj: t.Mapping[T, T2], iteratee: None = None) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in(obj: t.Sequence[T], iteratee: t.Callable[[T, int, t.List[T]], t.Any]) -> t.List[T]: ...
+
+
+@t.overload
+def for_in(obj: t.Sequence[T], iteratee: t.Callable[[T, int], t.Any]) -> t.List[T]: ...
+
+
+@t.overload
+def for_in(obj: t.Sequence[T], iteratee: t.Callable[[T], t.Any]) -> t.List[T]: ...
+
+
+@t.overload
+def for_in(obj: t.Sequence[T], iteratee: None = None) -> t.List[T]: ...
+
+
+def for_in(obj, iteratee=None):
+ """
+ Iterates over own and inherited enumerable properties of `obj`, executing `iteratee` for each
+ property.
+
+ Args:
+ obj: Object to process.
+ iteratee: Iteratee applied per iteration.
+
+ Returns:
+ `obj`.
+
+ Example:
+
+ >>> obj = {}
+ >>> def cb(v, k):
+ ... obj[k] = v
+ >>> results = for_in({"a": 1, "b": 2, "c": 3}, cb)
+ >>> results == {"a": 1, "b": 2, "c": 3}
+ True
+ >>> obj == {"a": 1, "b": 2, "c": 3}
+ True
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.0.0
+ Removed alias ``for_own``.
+ """
+ walk = (None for ret, _, _, _ in iteriteratee(obj, iteratee) if ret is False)
+ next(walk, None)
+ return obj
+
+
+@t.overload
+def for_in_right(
+ obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], t.Any]
+) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in_right(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in_right(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in_right(obj: t.Mapping[T, T2], iteratee: None = None) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def for_in_right(
+ obj: t.Sequence[T], iteratee: t.Callable[[T, int, t.List[T]], t.Any]
+) -> t.List[T]: ...
+
+
+@t.overload
+def for_in_right(obj: t.Sequence[T], iteratee: t.Callable[[T, int], t.Any]) -> t.List[T]: ...
+
+
+@t.overload
+def for_in_right(obj: t.Sequence[T], iteratee: t.Callable[[T], t.Any]) -> t.List[T]: ...
+
+
+@t.overload
+def for_in_right(obj: t.Sequence[T], iteratee: None = None) -> t.List[T]: ...
+
+
+def for_in_right(obj, iteratee=None):
+ """
+ This function is like :func:`for_in` except it iterates over the properties in reverse order.
+
+ Args:
+ obj: Object to process.
+ iteratee: Iteratee applied per iteration.
+
+ Returns:
+ `obj`.
+
+ Example:
+
+ >>> data = {"product": 1}
+ >>> def cb(v):
+ ... data["product"] *= v
+ >>> for_in_right([1, 2, 3, 4], cb)
+ [1, 2, 3, 4]
+ >>> data["product"] == 24
+ True
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.0.0
+ Removed alias ``for_own_right``.
+ """
+ walk = (None for ret, _, _, _ in iteriteratee(obj, iteratee, reverse=True) if ret is False)
+ next(walk, None)
+ return obj
+
+
+@t.overload
+def get(obj: t.List[T], path: int, default: T2) -> t.Union[T, T2]: ...
+
+
+@t.overload
+def get(obj: t.List[T], path: int, default: None = None) -> t.Union[T, None]: ...
+
+
+@t.overload
+def get(obj: t.Any, path: PathT, default: t.Any = None) -> t.Any: ...
+
+
+def get(obj: t.Any, path: PathT, default: t.Any = None) -> t.Any:
+ """
+ Get the value at any depth of a nested object based on the path described by `path`. If path
+ doesn't exist, `default` is returned.
+
+ Args:
+ obj: Object to process.
+ path: List or ``.`` delimited string of path describing path.
+ default: Default value to return if path doesn't exist. Defaults to ``None``.
+
+ Returns:
+ Value of `obj` at path.
+
+ Example:
+
+ >>> get({}, "a.b.c") is None
+ True
+ >>> get({"a": {"b": {"c": [1, 2, 3, 4]}}}, "a.b.c[1]")
+ 2
+ >>> get({"a": {"b": {"c": [1, 2, 3, 4]}}}, "a.b.c.1")
+ 2
+ >>> get({"a": {"b": [0, {"c": [1, 2]}]}}, "a.b.1.c.1")
+ 2
+ >>> get({"a": {"b": [0, {"c": [1, 2]}]}}, ["a", "b", 1, "c", 1])
+ 2
+ >>> get({"a": {"b": [0, {"c": [1, 2]}]}}, "a.b.1.c.2") is None
+ True
+
+ .. versionadded:: 2.0.0
+
+ .. versionchanged:: 2.2.0
+ Support escaping "." delimiter in single string path key.
+
+ .. versionchanged:: 3.3.0
+
+ - Added :func:`get` as main definition and :func:`get_path` as alias.
+ - Made :func:`deep_get` an alias.
+
+ .. versionchanged:: 3.4.7
+ Fixed bug where an iterable default was iterated over instead of being returned when an
+ object path wasn't found.
+
+ .. versionchanged:: 4.0.0
+
+ - Support attribute access on `obj` if item access fails.
+ - Removed aliases ``get_path`` and ``deep_get``.
+
+ .. versionchanged:: 4.7.6
+ Fixed bug where getattr is used on Mappings and Sequence in Python 3.5+
+ """
+ if default is UNSET:
+ # When NoValue given for default, then this method will raise if path is not present in obj.
+ sentinel = default
+ else:
+ # When a returnable default is given, use a sentinel value to detect when base_get() returns
+ # a default value for a missing path, so we can exit early from the loop and not mistakenly
+ # iterate over the default.
+ sentinel = object()
+
+ for key in to_path(path):
+ obj = base_get(obj, key, default=sentinel)
+
+ if obj is sentinel:
+ # Path doesn't exist so set return obj to the default.
+ obj = default
+ break
+
+ return obj
+
+
+def has(obj: t.Any, path: PathT) -> bool:
+ """
+ Checks if `path` exists as a key of `obj`.
+
+ Args:
+ obj: Object to test.
+ path: Path to test for. Can be a list of nested keys or a ``.`` delimited string of
+ path describing the path.
+
+ Returns:
+ Whether `obj` has `path`.
+
+ Example:
+
+ >>> has([1, 2, 3], 1)
+ True
+ >>> has({"a": 1, "b": 2}, "b")
+ True
+ >>> has({"a": 1, "b": 2}, "c")
+ False
+ >>> has({"a": {"b": [0, {"c": [1, 2]}]}}, "a.b.1.c.1")
+ True
+ >>> has({"a": {"b": [0, {"c": [1, 2]}]}}, "a.b.1.c.2")
+ False
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 3.0.0
+ Return ``False`` on ``ValueError`` when checking path.
+
+ .. versionchanged:: 3.3.0
+
+ - Added :func:`deep_has` as alias.
+ - Added :func:`has_path` as alias.
+
+ .. versionchanged:: 4.0.0
+ Removed aliases ``deep_has`` and ``has_path``.
+ """
+ try:
+ get(obj, path, default=UNSET)
+ exists = True
+ except (KeyError, IndexError, TypeError, ValueError):
+ exists = False
+
+ return exists
+
+
+@t.overload
+def invert(obj: t.Mapping[T, T2]) -> t.Dict[T2, T]: ...
+
+
+@t.overload
+def invert(obj: t.Union[t.Iterator[T], t.Sequence[T]]) -> t.Dict[T, int]: ...
+
+
+def invert(obj):
+ """
+ Creates an object composed of the inverted keys and values of the given object.
+
+ Args:
+ obj: Dict to invert.
+
+ Returns:
+ Inverted dict.
+
+ Example:
+
+ >>> results = invert({"a": 1, "b": 2, "c": 3})
+ >>> results == {1: "a", 2: "b", 3: "c"}
+ True
+
+ Note:
+ Assumes `obj` values are hashable as ``dict`` keys.
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 2.0.0
+ Added ``multivalue`` argument.
+
+ .. versionchanged:: 4.0.0
+ Moved ``multivalue=True`` functionality to :func:`invert_by`.
+ """
+ return {value: key for key, value in iterator(obj)}
+
+
+@t.overload
+def invert_by(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2], T3]) -> t.Dict[T3, t.List[T]]: ...
+
+
+@t.overload
+def invert_by(obj: t.Mapping[T, T2], iteratee: None = None) -> t.Dict[T2, t.List[T]]: ...
+
+
+@t.overload
+def invert_by(
+ obj: t.Union[t.Iterator[T], t.Sequence[T]], iteratee: t.Callable[[T], T2]
+) -> t.Dict[T2, t.List[int]]: ...
+
+
+@t.overload
+def invert_by(
+ obj: t.Union[t.Iterator[T], t.Sequence[T]], iteratee: None = None
+) -> t.Dict[T, t.List[int]]: ...
+
+
+def invert_by(obj, iteratee=None):
+ """
+ This method is like :func:`invert` except that the inverted object is generated from the results
+ of running each element of object through iteratee. The corresponding inverted value of each
+ inverted key is a list of keys responsible for generating the inverted value. The iteratee is
+ invoked with one argument: ``(value)``.
+
+ Args:
+ obj: Object to invert.
+ iteratee: Iteratee applied per iteration.
+
+ Returns:
+ Inverted dict.
+
+ Example:
+
+ >>> obj = {"a": 1, "b": 2, "c": 1}
+ >>> results = invert_by(obj) # {1: ['a', 'c'], 2: ['b']}
+ >>> set(results[1]) == set(["a", "c"])
+ True
+ >>> set(results[2]) == set(["b"])
+ True
+ >>> results2 = invert_by(obj, lambda value: "group" + str(value))
+ >>> results2["group1"] == results[1]
+ True
+ >>> results2["group2"] == results[2]
+ True
+
+ Note:
+ Assumes `obj` values are hashable as ``dict`` keys.
+
+ .. versionadded:: 4.0.0
+ """
+ callback = pyd.iteratee(iteratee)
+ result = {}
+
+ for key, value in iterator(obj):
+ result.setdefault(callback(value), []).append(key)
+
+ return result
+
+
+def invoke(obj: t.Any, path: PathT, *args: t.Any, **kwargs: t.Any) -> t.Any:
+ """
+ Invokes the method at path of object.
+
+ Args:
+ obj: The object to query.
+ path: The path of the method to invoke.
+ args: Arguments to pass to method call.
+ kwargs: Keyword arguments to pass to method call.
+
+ Returns:
+ Result of the invoked method.
+
+ Example:
+
+ >>> obj = {"a": [{"b": {"c": [1, 2, 3, 4]}}]}
+ >>> invoke(obj, "a[0].b.c.pop", 1)
+ 2
+ >>> obj
+ {'a': [{'b': {'c': [1, 3, 4]}}]}
+
+ .. versionadded:: 1.0.0
+ """
+ paths = to_path(path)
+ target_path = pyd.initial(paths)
+ method_name = pyd.last(paths)
+
+ try:
+ # potential error is caught
+ method = getattr(get(obj, target_path), method_name) # type: ignore
+ except AttributeError:
+ ret = None
+ else:
+ ret = method(*args, **kwargs)
+
+ return ret
+
+
+@t.overload
+def keys(obj: t.Iterable[T]) -> t.List[T]: ...
+
+
+@t.overload
+def keys(obj: t.Any) -> t.List[t.Any]: ...
+
+
+def keys(obj):
+ """
+ Creates a list composed of the keys of `obj`.
+
+ Args:
+ obj: Object to extract keys from.
+
+ Returns:
+ List of keys.
+
+ Example:
+
+ >>> keys([1, 2, 3])
+ [0, 1, 2]
+ >>> set(keys({"a": 1, "b": 2, "c": 3})) == set(["a", "b", "c"])
+ True
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 1.1.0
+ Added ``keys_in`` as alias.
+
+ .. versionchanged:: 4.0.0
+ Removed alias ``keys_in``.
+ """
+ return [key for key, _ in iterator(obj)]
+
+
+@t.overload
+def map_keys(
+ obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], T3]
+) -> t.Dict[T3, T2]: ...
+
+
+@t.overload
+def map_keys(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], T3]) -> t.Dict[T3, T2]: ...
+
+
+@t.overload
+def map_keys(obj: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], T3]) -> t.Dict[T3, T2]: ...
+
+
+@t.overload
+def map_keys(
+ obj: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], T2]
+) -> t.Dict[T2, T]: ...
+
+
+@t.overload
+def map_keys(obj: t.Iterable[T], iteratee: t.Callable[[T, int], T2]) -> t.Dict[T2, T]: ...
+
+
+@t.overload
+def map_keys(obj: t.Iterable[T], iteratee: t.Callable[[T], T2]) -> t.Dict[T2, T]: ...
+
+
+@t.overload
+def map_keys(
+ obj: t.Iterable[t.Any], iteratee: t.Union[IterateeObjT, None] = None
+) -> t.Dict[t.Any, t.Any]: ...
+
+
+def map_keys(obj, iteratee=None):
+ """
+ The opposite of :func:`map_values`, this method creates an object with the same values as object
+ and keys generated by running each own enumerable string keyed property of object through
+ iteratee. The iteratee is invoked with three arguments: ``(value, key, object)``.
+
+ Args:
+ obj: Object to map.
+ iteratee: Iteratee applied per iteration.
+
+ Returns:
+ Results of running `obj` through `iteratee`.
+
+ Example:
+
+ >>> callback = lambda value, key: key * 2
+ >>> results = map_keys({"a": 1, "b": 2, "c": 3}, callback)
+ >>> results == {"aa": 1, "bb": 2, "cc": 3}
+ True
+
+ .. versionadded:: 3.3.0
+ """
+ return {result: value for result, value, _, _ in iteriteratee(obj, iteratee)}
+
+
+@t.overload
+def map_values(
+ obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], T3]
+) -> t.Dict[T, T3]: ...
+
+
+@t.overload
+def map_values(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], T3]) -> t.Dict[T, T3]: ...
+
+
+@t.overload
+def map_values(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2], T3]) -> t.Dict[T, T3]: ...
+
+
+@t.overload
+def map_values(
+ obj: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], T2]
+) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def map_values(obj: t.Iterable[T], iteratee: t.Callable[[T, int], T2]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def map_values(obj: t.Iterable[T], iteratee: t.Callable[[T], T2]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def map_values(
+ obj: t.Iterable[t.Any], iteratee: t.Union[IterateeObjT, None] = None
+) -> t.Dict[t.Any, t.Any]: ...
+
+
+def map_values(obj, iteratee=None):
+ """
+ Creates an object with the same keys as object and values generated by running each string keyed
+ property of object through iteratee. The iteratee is invoked with three arguments: ``(value,
+ key, object)``.
+
+ Args:
+ obj: Object to map.
+ iteratee: Iteratee applied per iteration.
+
+ Returns:
+ Results of running `obj` through `iteratee`.
+
+ Example:
+
+ >>> results = map_values({"a": 1, "b": 2, "c": 3}, lambda x: x * 2)
+ >>> results == {"a": 2, "b": 4, "c": 6}
+ True
+ >>> results = map_values({"a": 1, "b": {"d": 4}, "c": 3}, {"d": 4})
+ >>> results == {"a": False, "b": True, "c": False}
+ True
+
+ .. versionadded:: 1.0.0
+ """
+ return {key: result for result, _, key, _ in iteriteratee(obj, iteratee)}
+
+
+def map_values_deep(
+ obj: t.Iterable[t.Any],
+ iteratee: t.Union[t.Callable[..., t.Any], None] = None,
+ property_path: t.Any = UNSET,
+) -> t.Any:
+ """
+ Map all non-object values in `obj` with return values from `iteratee`. The iteratee is invoked
+ with two arguments: ``(obj_value, property_path)`` where ``property_path`` contains the list of
+ path keys corresponding to the path of ``obj_value``.
+
+ Args:
+ obj: Object to map.
+ iteratee: Iteratee applied to each value.
+ property_path: Path key(s) to access.
+
+ Returns:
+ The modified object.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> x = {"a": 1, "b": {"c": 2}}
+ >>> y = map_values_deep(x, lambda val: val * 2)
+ >>> y == {"a": 2, "b": {"c": 4}}
+ True
+ >>> z = map_values_deep(x, lambda val, props: props)
+ >>> z == {"a": ["a"], "b": {"c": ["b", "c"]}}
+ True
+
+ .. versionadded: 2.2.0
+
+ .. versionchanged:: 3.0.0
+ Allow iteratees to accept partial arguments.
+
+ .. versionchanged:: 4.0.0
+ Renamed from ``deep_map_values`` to ``map_values_deep``.
+ """
+ properties = to_path(property_path)
+
+ if pyd.is_object(obj):
+
+ def deep_iteratee(value, key):
+ return map_values_deep(value, iteratee, pyd.flatten([properties, key]))
+
+ return assign(obj, map_values(obj, deep_iteratee)) # type: ignore
+ else:
+ return callit(iteratee, obj, properties)
+
+
+def apply(obj: T, func: t.Callable[[T], T2]) -> T2:
+ """
+ Returns the result of calling `func` on `obj`. Particularly useful to pass
+ `obj` through a function during a method chain.
+
+ Args:
+ obj: Object to apply function to
+ func: Function called with `obj`.
+
+ Returns:
+ Results of ``func(value)``.
+
+ Example:
+
+ >>> apply(5, lambda x: x * 2)
+ 10
+
+ .. versionadded:: 8.0.0
+ """
+ return func(obj)
+
+
+def apply_if(obj: T, func: t.Callable[[T], T2], predicate: t.Callable[[T], bool]) -> t.Union[T, T2]:
+ """
+ Apply `func` to `obj` if `predicate` returns `True`.
+
+ Args:
+ obj: Object to apply `func` to.
+ func: Function to apply to `obj`.
+ predicate: Predicate applied to `obj`.
+
+ Returns:
+ Result of applying `func` to `obj` or `obj`.
+
+ Example:
+
+ >>> apply_if(2, lambda x: x * 2, lambda x: x > 1)
+ 4
+ >>> apply_if(2, lambda x: x * 2, lambda x: x < 1)
+ 2
+
+ .. versionadded:: 8.0.0
+ """
+ return func(obj) if predicate(obj) else obj
+
+
+def apply_if_not_none(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:
+
+ >>> apply_if_not_none(2, lambda x: x * 2)
+ 4
+ >>> apply_if_not_none(None, lambda x: x * 2) is None
+ True
+
+ .. versionadded:: 8.0.0
+ """
+ return apply_if(obj, func, lambda x: x is not None) # type: ignore
+
+
+@t.overload
+def apply_catch(
+ obj: T, func: t.Callable[[T], T2], exceptions: t.Iterable[t.Type[Exception]], default: T3
+) -> t.Union[T2, T3]: ...
+
+
+@t.overload
+def apply_catch(
+ obj: T,
+ func: t.Callable[[T], T2],
+ exceptions: t.Iterable[t.Type[Exception]],
+ default: Unset = UNSET,
+) -> t.Union[T, T2]: ...
+
+
+def apply_catch(obj, func, exceptions, default=UNSET):
+ """
+ Tries to apply `func` to `obj` if any of the exceptions in `excs` are raised, return `default`
+ or `obj` if not set.
+
+ Args:
+ obj: Object to apply `func` to.
+ func: Function to apply to `obj`.
+ excs: Exceptions to catch.
+ default: Value to return if exception is raised.
+
+ Returns:
+ Result of applying `func` to `obj` or ``default``.
+
+ Example:
+
+ >>> apply_catch(2, lambda x: x * 2, [ValueError])
+ 4
+ >>> apply_catch(2, lambda x: x / 0, [ZeroDivisionError], "error")
+ 'error'
+ >>> apply_catch(2, lambda x: x / 0, [ZeroDivisionError])
+ 2
+
+ .. versionadded:: 8.0.0
+ """
+ try:
+ return func(obj)
+ except tuple(exceptions):
+ return obj if default is UNSET else default
+
+
+@t.overload
+def merge(
+ obj: t.Mapping[T, T2], *sources: t.Mapping[T3, T4]
+) -> t.Dict[t.Union[T, T3], t.Union[T2, T4]]: ...
+
+
+@t.overload
+def merge(obj: t.Sequence[T], *sources: t.Sequence[T2]) -> t.List[t.Union[T, T2]]: ...
+
+
+def merge(obj, *sources):
+ """
+ Recursively merges properties of the source object(s) into the destination object. Subsequent
+ sources will overwrite property assignments of previous sources.
+
+ Args:
+ obj: Destination object to merge source(s) into.
+ sources: Source objects to merge from. subsequent sources overwrite previous ones.
+
+ Returns:
+ Merged object.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> obj = {"a": 2}
+ >>> obj2 = merge(obj, {"a": 1}, {"b": 2, "c": 3}, {"d": 4})
+ >>> obj2 == {"a": 1, "b": 2, "c": 3, "d": 4}
+ True
+ >>> obj is obj2
+ True
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 2.3.2
+ Apply :func:`clone_deep` to each `source` before assigning to `obj`.
+
+ .. versionchanged:: 2.3.2
+ Allow `iteratee` to be passed by reference if it is the last positional argument.
+
+ .. versionchanged:: 4.0.0
+ Moved iteratee argument to :func:`merge_with`.
+
+ .. versionchanged:: 4.9.3
+ Fixed regression in v4.8.0 that caused exception when `obj` was ``None``.
+ """
+ return merge_with(obj, *sources)
+
+
+def merge_with(obj: t.Any, *sources: t.Any, **kwargs: t.Any) -> t.Any:
+ """
+ This method is like :func:`merge` except that it accepts customizer which is invoked to produce
+ the merged values of the destination and source properties. If customizer returns ``None``,
+ merging is handled by this method instead. The customizer is invoked with five arguments:
+ ``(obj_value, src_value, key, obj, source)``.
+
+ Args:
+ obj: Destination object to merge source(s) into.
+ sources: Source objects to merge from. subsequent sources
+ overwrite previous ones.
+
+ Keyword Args:
+ iteratee: Iteratee function to handle merging
+ (must be passed in as keyword argument).
+
+ Returns:
+ Merged object.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> cbk = lambda obj_val, src_val: obj_val + src_val
+ >>> obj1 = {"a": [1], "b": [2]}
+ >>> obj2 = {"a": [3], "b": [4]}
+ >>> res = merge_with(obj1, obj2, cbk)
+ >>> obj1 == {"a": [1, 3], "b": [2, 4]}
+ True
+
+ .. versionadded:: 4.0.0
+
+ .. versionchanged:: 4.9.3
+ Fixed regression in v4.8.0 that caused exception when `obj` was ``None``.
+ """
+ if obj is None:
+ return None
+
+ list_sources = list(sources)
+ iteratee = kwargs.pop("iteratee", None)
+
+ if iteratee is None and list_sources and callable(list_sources[-1]):
+ iteratee = list_sources.pop()
+
+ list_sources = [copy.deepcopy(source) for source in list_sources]
+
+ if callable(iteratee):
+ iteratee = partial(callit, iteratee, argcount=getargcount(iteratee, maxargs=5))
+ else:
+ iteratee = None
+
+ return _merge_with(obj, *list_sources, iteratee=iteratee, **kwargs)
+
+
+def _merge_with(obj, *sources, **kwargs):
+ iteratee = kwargs.get("iteratee")
+ setter = kwargs.get("_setter")
+
+ if setter is None:
+ setter = base_set
+
+ for source in sources:
+ for key, src_value in iterator(source):
+ obj_value = base_get(obj, key, default=None)
+ all_sequences = isinstance(src_value, list) and isinstance(obj_value, list)
+ all_mappings = isinstance(src_value, dict) and isinstance(obj_value, dict)
+
+ _result = None
+ if iteratee:
+ _result = iteratee(obj_value, src_value, key, obj, source)
+
+ if _result is not None:
+ result = _result
+ elif all_sequences or all_mappings:
+ result = _merge_with(obj_value, src_value, iteratee=iteratee, _setter=setter)
+ else:
+ result = src_value
+
+ setter(obj, key, result)
+
+ return obj
+
+
+@t.overload
+def omit(obj: t.Mapping[T, T2], *properties: PathT) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def omit(obj: t.Union[t.Iterator[T], t.Sequence[T]], *properties: PathT) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def omit(obj: t.Any, *properties: PathT) -> t.Dict[t.Any, t.Any]: ...
+
+
+def omit(obj, *properties):
+ """
+ The opposite of :func:`pick`. This method creates an object composed of the property paths of
+ `obj` that are not omitted.
+
+ Args:
+ obj: Object to process.
+ *properties: Property values to omit.
+
+ Returns:
+ Results of omitting properties.
+
+ Example:
+
+ >>> omit({"a": 1, "b": 2, "c": 3}, "b", "c") == {"a": 1}
+ True
+ >>> omit({"a": 1, "b": 2, "c": 3}, ["a", "c"]) == {"b": 2}
+ True
+ >>> omit([1, 2, 3, 4], 0, 3) == {1: 2, 2: 3}
+ True
+ >>> omit({"a": {"b": {"c": "d"}}}, "a.b.c") == {"a": {"b": {}}}
+ True
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.0.0
+ Moved iteratee argument to :func:`omit_by`.
+
+ .. versionchanged:: 4.2.0
+ Support deep paths.
+ """
+ return omit_by(obj, pyd.flatten(properties))
+
+
+@t.overload
+def omit_by(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def omit_by(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def omit_by(obj: t.Dict[T, T2], iteratee: None = None) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def omit_by(
+ obj: t.Union[t.Iterator[T], t.Sequence[T]], iteratee: t.Callable[[T, int], t.Any]
+) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def omit_by(
+ obj: t.Union[t.Iterator[T], t.Sequence[T]], iteratee: t.Callable[[T], t.Any]
+) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def omit_by(obj: t.List[T], iteratee: None = None) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def omit_by(
+ obj: t.Any, iteratee: t.Union[t.Callable[..., t.Any], None] = None
+) -> t.Dict[t.Any, t.Any]: ...
+
+
+def omit_by(obj, iteratee=None):
+ """
+ The opposite of :func:`pick_by`. This method creates an object composed of the string keyed
+ properties of object that predicate doesn't return truthy for. The predicate is invoked with two
+ arguments: ``(value, key)``.
+
+ Args:
+ obj: Object to process.
+ iteratee: Iteratee used to determine which properties to omit.
+
+ Returns:
+ Results of omitting properties.
+
+ Example:
+
+ >>> omit_by({"a": 1, "b": "2", "c": 3}, lambda v: isinstance(v, int))
+ {'b': '2'}
+
+ .. versionadded:: 4.0.0
+
+ .. versionchanged:: 4.2.0
+ Support deep paths for `iteratee`.
+ """
+ if not callable(iteratee):
+ paths = pyd.map_(iteratee, to_path)
+
+ if any(len(path) > 1 for path in paths):
+ cloned = clone_deep(obj)
+ else:
+ cloned = to_dict(obj)
+
+ def _unset(obj, path):
+ pyd.unset(obj, path)
+ return obj
+
+ ret = pyd.reduce_(paths, _unset, cloned)
+ else:
+ argcount = getargcount(iteratee, maxargs=2)
+
+ ret = {
+ key: value
+ for key, value in iterator(obj)
+ if not callit(iteratee, value, key, argcount=argcount)
+ }
+
+ return ret
+
+
+def parse_int(value: t.Any, radix: t.Union[int, None] = None) -> t.Union[int, None]:
+ """
+ Converts the given `value` into an integer of the specified `radix`. If `radix` is falsey, a
+ radix of ``10`` is used unless the `value` is a hexadecimal, in which case a radix of 16 is
+ used.
+
+ Args:
+ value: Value to parse.
+ radix: Base to convert to.
+
+ Returns:
+ Integer if parsable else ``None``.
+
+ Example:
+
+ >>> parse_int("5")
+ 5
+ >>> parse_int("12", 8)
+ 10
+ >>> parse_int("x") is None
+ True
+
+ .. versionadded:: 1.0.0
+ """
+ if not radix and pyd.is_string(value):
+ try:
+ # Check if value is hexadecimal and if so use base-16 conversion.
+ int(value, 16)
+ except ValueError:
+ pass
+ else:
+ radix = 16
+
+ if not radix:
+ radix = 10
+
+ try:
+ # NOTE: Must convert value to string when supplying radix to int(). Dropping radix arg when
+ # 10 is needed to allow floats to parse correctly.
+ args = (value,) if radix == 10 else (to_string(value), radix)
+ parsed = int(*args)
+ except (ValueError, TypeError):
+ parsed = None
+
+ return parsed
+
+
+@t.overload
+def pick(obj: t.Mapping[T, T2], *properties: PathT) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def pick(obj: t.Union[t.Tuple[T, ...], t.List[T]], *properties: PathT) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def pick(obj: t.Any, *properties: PathT) -> t.Dict[t.Any, t.Any]: ...
+
+
+def pick(obj, *properties):
+ """
+ Creates an object composed of the picked object properties.
+
+ Args:
+ obj: Object to pick from.
+ properties: Property values to pick.
+
+ Returns:
+ Dict containing picked properties.
+
+ Example:
+
+ >>> pick({"a": 1, "b": 2, "c": 3}, "a", "b") == {"a": 1, "b": 2}
+ True
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.0.0
+ Moved iteratee argument to :func:`pick_by`.
+ """
+ return pick_by(obj, pyd.flatten(properties))
+
+
+@t.overload
+def pick_by(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def pick_by(obj: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], t.Any]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def pick_by(obj: t.Dict[T, T2], iteratee: None = None) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def pick_by(
+ obj: t.Union[t.Tuple[T, ...], t.List[T]], iteratee: t.Callable[[T, int], t.Any]
+) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def pick_by(
+ obj: t.Union[t.Tuple[T, ...], t.List[T]], iteratee: t.Callable[[T], t.Any]
+) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def pick_by(obj: t.Union[t.Tuple[T, ...], t.List[T]], iteratee: None = None) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def pick_by(
+ obj: t.Any, iteratee: t.Union[t.Callable[..., t.Any], None] = None
+) -> t.Dict[t.Any, t.Any]: ...
+
+
+def pick_by(obj, iteratee=None):
+ """
+ Creates an object composed of the object properties predicate returns truthy for. The predicate
+ is invoked with two arguments: ``(value, key)``.
+
+ Args:
+ obj: Object to pick from.
+ iteratee: Iteratee used to determine which properties to pick.
+
+ Returns:
+ Dict containing picked properties.
+
+ Example:
+
+ >>> obj = {"a": 1, "b": "2", "c": 3}
+ >>> pick_by(obj, lambda v: isinstance(v, int)) == {"a": 1, "c": 3}
+ True
+
+ .. versionadded:: 4.0.0
+ """
+ obj = to_dict(obj)
+
+ if iteratee is None or callable(iteratee):
+ paths = keys(obj)
+ if iteratee is None:
+ iteratee = pyd.identity
+ argcount = 1
+ else:
+ argcount = getargcount(iteratee, maxargs=2)
+ else:
+ paths = iteratee if iteratee is not None else []
+
+ def iteratee(value, path): # pylint: disable=function-redefined
+ return has(obj, path)
+
+ argcount = 2
+
+ result = {}
+
+ for path in paths:
+ value = get(obj, path)
+
+ if callit(iteratee, value, path, argcount=argcount):
+ set_(result, path, value)
+
+ return result
+
+
+def rename_keys(obj: t.Dict[T, T2], key_map: t.Dict[t.Any, T3]) -> t.Dict[t.Union[T, T3], T2]:
+ """
+ Rename the keys of `obj` using `key_map` and return new object.
+
+ Args:
+ obj: Object to rename.
+ key_map: Renaming map whose keys correspond to existing keys in `obj` and whose
+ values are the new key name.
+
+ Returns:
+ Renamed `obj`.
+
+ Example:
+
+ >>> obj = rename_keys({"a": 1, "b": 2, "c": 3}, {"a": "A", "b": "B"})
+ >>> obj == {"A": 1, "B": 2, "c": 3}
+ True
+
+ .. versionadded:: 2.0.0
+ """
+ return {key_map.get(key, key): value for key, value in obj.items()}
+
+
+def set_(obj: T, path: PathT, value: t.Any) -> T:
+ """
+ Sets the value of an object described by `path`. If any part of the object path doesn't exist,
+ it will be created.
+
+ Args:
+ obj: Object to modify.
+ path: Target path to set value to.
+ value: Value to set.
+
+ Returns:
+ Modified `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> set_({}, "a.b.c", 1)
+ {'a': {'b': {'c': 1}}}
+ >>> set_({}, "a.0.c", 1)
+ {'a': {'0': {'c': 1}}}
+ >>> set_([1, 2], "[2][0]", 1)
+ [1, 2, [1]]
+ >>> set_({}, "a.b[0].c", 1)
+ {'a': {'b': [{'c': 1}]}}
+
+ .. versionadded:: 2.2.0
+
+ .. versionchanged:: 3.3.0
+ Added :func:`set_` as main definition and :func:`deep_set` as alias.
+
+ .. versionchanged:: 4.0.0
+
+ - Modify `obj` in place.
+ - Support creating default path values as ``list`` or ``dict`` based on whether key or index
+ substrings are used.
+ - Remove alias ``deep_set``.
+ """
+ return set_with(obj, path, value)
+
+
+def set_with(
+ obj: T, path: PathT, value: t.Any, customizer: t.Union[t.Callable[..., t.Any], None] = None
+) -> T:
+ """
+ This method is like :func:`set_` except that it accepts customizer which is invoked to produce
+ the objects of path. If customizer returns undefined path creation is handled by the method
+ instead. The customizer is invoked with three arguments: ``(nested_value, key, nested_object)``.
+
+ Args:
+ obj: Object to modify.
+ path: Target path to set value to.
+ value: Value to set.
+ customizer: The function to customize assigned values.
+
+ Returns:
+ Modified `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> set_with({}, "[0][1]", "a", lambda: {})
+ {0: {1: 'a'}}
+
+ .. versionadded:: 4.0.0
+
+ .. versionchanged:: 4.3.1
+ Fixed bug where a callable `value` was called when being set.
+ """
+ return update_with(obj, path, pyd.constant(value), customizer=customizer)
+
+
+def to_boolean(
+ obj: t.Any,
+ true_values: t.Tuple[str, ...] = ("true", "1"),
+ false_values: t.Tuple[str, ...] = ("false", "0"),
+) -> t.Union[bool, None]:
+ """
+ Convert `obj` to boolean. This is not like the builtin ``bool`` function. By default, commonly
+ considered strings values are converted to their boolean equivalent, i.e., ``'0'`` and
+ ``'false'`` are converted to ``False`` while ``'1'`` and ``'true'`` are converted to ``True``.
+ If a string value is provided that isn't recognized as having a common boolean conversion, then
+ the returned value is ``None``. Non-string values of `obj` are converted using ``bool``.
+ Optionally, `true_values` and `false_values` can be overridden but each value must be a string.
+
+ Args:
+ obj: Object to convert.
+ true_values: Values to consider ``True``. Each value must be a string.
+ Comparision is case-insensitive. Defaults to ``('true', '1')``.
+ false_values: Values to consider ``False``. Each value must be a string.
+ Comparision is case-insensitive. Defaults to ``('false', '0')``.
+
+ Returns:
+ Boolean value of `obj`.
+
+ Example:
+
+ >>> to_boolean("true")
+ True
+ >>> to_boolean("1")
+ True
+ >>> to_boolean("false")
+ False
+ >>> to_boolean("0")
+ False
+ >>> assert to_boolean("a") is None
+
+ .. versionadded:: 3.0.0
+ """
+ if pyd.is_string(obj):
+ obj = obj.strip()
+
+ def boolean_match(text, vals):
+ if text.lower() in [val.lower() for val in vals]:
+ return True
+ else:
+ return re.match("|".join(vals), text)
+
+ if true_values and boolean_match(obj, true_values):
+ value = True
+ elif false_values and boolean_match(obj, false_values):
+ value = False
+ else:
+ value = None
+ else:
+ value = bool(obj)
+
+ return value
+
+
+@t.overload
+def to_dict(obj: t.Mapping[T, T2]) -> t.Dict[T, T2]: ...
+
+
+@t.overload
+def to_dict(obj: t.Union[t.Iterator[T], t.Sequence[T]]) -> t.Dict[int, T]: ...
+
+
+@t.overload
+def to_dict(obj: t.Any) -> t.Dict[t.Any, t.Any]: ...
+
+
+def to_dict(obj):
+ """
+ Convert `obj` to ``dict`` by creating a new ``dict`` using `obj` keys and values.
+
+ Args:
+ obj: Object to convert.
+
+ Returns:
+ Object converted to ``dict``.
+
+ Example:
+
+ >>> obj = {"a": 1, "b": 2}
+ >>> obj2 = to_dict(obj)
+ >>> obj2 == obj
+ True
+ >>> obj2 is not obj
+ True
+
+ .. versionadded:: 3.0.0
+
+ .. versionchanged:: 4.0.0
+ Removed alias ``to_plain_object``.
+
+ .. versionchanged:: 4.2.0
+ Use ``pydash.helpers.iterator`` to generate key/value pairs.
+
+ .. versionchanged:: 4.7.1
+ Try to convert to ``dict`` using ``dict()`` first, then fallback to using
+ ``pydash.helpers.iterator``.
+ """
+ return dict(iterator(obj))
+
+
+def to_integer(obj: t.Any) -> int:
+ """
+ Converts `obj` to an integer.
+
+ Args:
+ obj: Object to convert.
+
+ Returns:
+ Converted integer or ``0`` if it can't be converted.
+
+ Example:
+
+ >>> to_integer(3.2)
+ 3
+ >>> to_integer("3.2")
+ 3
+ >>> to_integer("3.9")
+ 3
+ >>> to_integer("invalid")
+ 0
+
+ .. versionadded:: 4.0.0
+ """
+ try:
+ # Convert to float first to handle converting floats as string since int('1.1') would fail
+ # but this won't.
+ num = int(float(obj))
+ except (ValueError, TypeError):
+ num = 0
+
+ return num
+
+
+@t.overload
+def to_list(obj: t.Dict[t.Any, T], split_strings: bool = True) -> t.List[T]: ...
+
+
+@t.overload
+def to_list(obj: t.Iterable[T], split_strings: bool = True) -> t.List[T]: ...
+
+
+@t.overload
+def to_list(obj: T, split_strings: bool = True) -> t.List[T]: ...
+
+
+def to_list(obj, split_strings=True):
+ """
+ Converts an obj, an iterable or a single item to a list.
+
+ Args:
+ obj: Object to convert item or wrap.
+ split_strings: Whether to split strings into single chars. Defaults to
+ ``True``.
+
+ Returns:
+ Converted obj or wrapped item.
+
+ Example:
+
+ >>> results = to_list({"a": 1, "b": 2, "c": 3})
+ >>> assert set(results) == set([1, 2, 3])
+
+ >>> to_list((1, 2, 3, 4))
+ [1, 2, 3, 4]
+
+ >>> to_list(1)
+ [1]
+
+ >>> to_list([1])
+ [1]
+
+ >>> to_list(a for a in [1, 2, 3])
+ [1, 2, 3]
+
+ >>> to_list("cat")
+ ['c', 'a', 't']
+
+ >>> to_list("cat", split_strings=False)
+ ['cat']
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.3.0
+
+ - Wrap non-iterable items in a list.
+ - Convert other iterables to list.
+ - Byte objects are returned as single character strings in Python 3.
+ """
+ if isinstance(obj, list):
+ return obj[:]
+ elif isinstance(obj, dict):
+ return obj.values()
+ elif not split_strings and isinstance(obj, (str, bytes)):
+ return [obj]
+ elif split_strings and isinstance(obj, bytes):
+ # in python3 iterating over bytes gives integers instead of strings
+ return list(chr(c) if isinstance(c, int) else c for c in obj)
+ else:
+ try:
+ return list(obj)
+ except TypeError:
+ return [obj]
+
+
+def to_number(obj: t.Any, precision: int = 0) -> t.Union[float, None]:
+ """
+ Convert `obj` to a number. All numbers are retuned as ``float``. If precision is negative, round
+ `obj` to the nearest positive integer place. If `obj` can't be converted to a number, ``None``
+ is returned.
+
+ Args:
+ obj: Object to convert.
+ precision: Precision to round number to. Defaults to ``0``.
+
+ Returns:
+ Converted number or ``None`` if it can't be converted.
+
+ Example:
+
+ >>> to_number("1234.5678")
+ 1235.0
+ >>> to_number("1234.5678", 4)
+ 1234.5678
+ >>> to_number(1, 2)
+ 1.0
+
+ .. versionadded:: 3.0.0
+ """
+ try:
+ factor = pow(10, precision)
+
+ if precision < 0:
+ # Round down since negative `precision` means we are going to the nearest positive
+ # integer place.
+ rounder: t.Callable[..., t.Any] = math.floor
+ else:
+ rounder = round
+
+ num = rounder(float(obj) * factor) / factor
+ except Exception:
+ num = None
+
+ return num
+
+
+@t.overload
+def to_pairs(obj: t.Mapping[T, T2]) -> t.List[t.Tuple[T, T2]]: ...
+
+
+@t.overload
+def to_pairs(obj: t.Union[t.Iterator[T], t.Sequence[T]]) -> t.List[t.Tuple[int, T]]: ...
+
+
+@t.overload
+def to_pairs(obj: t.Any) -> t.List[t.Any]: ...
+
+
+def to_pairs(obj):
+ """
+ Creates a list of tuples of an object's key-value pairs, i.e.,
+ ``[(key1, value1), (key2, value2)]``.
+
+ Args:
+ obj: Object to process.
+
+ Returns:
+ List of tuples of the object's key-value pairs.
+
+ Example:
+
+ >>> to_pairs([1, 2, 3, 4])
+ [(0, 1), (1, 2), (2, 3), (3, 4)]
+ >>> to_pairs({"a": 1})
+ [('a', 1)]
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 4.0.0
+ Renamed from ``pairs`` to ``to_pairs``.
+
+ .. versionchanged:: 8.0.0
+ Returning list of tuples instead of list of lists.
+ """
+ return [(key, value) for key, value in iterator(obj)]
+
+
+def to_string(obj: t.Any) -> str:
+ """
+ Converts an object to string.
+
+ Args:
+ obj: Object to convert.
+
+ Returns:
+ String representation of `obj`.
+
+ Example:
+
+ >>> to_string(1) == "1"
+ True
+ >>> to_string(None) == ""
+ True
+ >>> to_string([1, 2, 3]) == "[1, 2, 3]"
+ True
+ >>> to_string("a") == "a"
+ True
+
+ .. versionadded:: 2.0.0
+
+ .. versionchanged:: 3.0.0
+ Convert ``None`` to empty string.
+ """
+ if pyd.is_string(obj):
+ res = obj
+ elif obj is None:
+ res = ""
+ else:
+ res = str(obj)
+ return res
+
+
+@t.overload
+def transform(
+ obj: t.Mapping[T, T2], iteratee: t.Callable[[T3, T2, T, t.Dict[T, T2]], t.Any], accumulator: T3
+) -> T3: ...
+
+
+@t.overload
+def transform(
+ obj: t.Mapping[T, T2], iteratee: t.Callable[[T3, T2, T], t.Any], accumulator: T3
+) -> T3: ...
+
+
+@t.overload
+def transform(
+ obj: t.Mapping[t.Any, T2], iteratee: t.Callable[[T3, T2], t.Any], accumulator: T3
+) -> T3: ...
+
+
+@t.overload
+def transform(
+ obj: t.Mapping[t.Any, t.Any], iteratee: t.Callable[[T3], t.Any], accumulator: T3
+) -> T3: ...
+
+
+@t.overload
+def transform(
+ obj: t.Iterable[T], iteratee: t.Callable[[T3, T, int, t.List[T]], t.Any], accumulator: T3
+) -> T3: ...
+
+
+@t.overload
+def transform(
+ obj: t.Iterable[T], iteratee: t.Callable[[T3, T, int], t.Any], accumulator: T3
+) -> T3: ...
+
+
+@t.overload
+def transform(obj: t.Iterable[T], iteratee: t.Callable[[T3, T], t.Any], accumulator: T3) -> T3: ...
+
+
+@t.overload
+def transform(obj: t.Iterable[t.Any], iteratee: t.Callable[[T3], t.Any], accumulator: T3) -> T3: ...
+
+
+@t.overload
+def transform(obj: t.Any, iteratee: t.Any = None, accumulator: t.Any = None) -> t.Any: ...
+
+
+def transform(obj, iteratee=None, accumulator=None):
+ """
+ An alernative to :func:`pydash.collections.reduce`, this method transforms `obj` to a new
+ accumulator object which is the result of running each of its properties through an iteratee,
+ with each iteratee execution potentially mutating the accumulator object. The iteratee is
+ invoked with four arguments: ``(accumulator, value, key, object)``. Iteratees may exit iteration
+ early by explicitly returning ``False``.
+
+ Args:
+ obj: Object to process.
+ iteratee: Iteratee applied per iteration.
+ accumulator: Accumulated object. Defaults to ``list``.
+
+ Returns:
+ Accumulated object.
+
+ Example:
+
+ >>> transform([1, 2, 3, 4], lambda acc, v, k: acc.append((k, v)))
+ [(0, 1), (1, 2), (2, 3), (3, 4)]
+
+ .. versionadded:: 1.0.0
+ """
+ if iteratee is None:
+ iteratee = pyd.identity
+ argcount = 1
+ else:
+ argcount = getargcount(iteratee, maxargs=4)
+
+ if accumulator is None:
+ accumulator = []
+
+ walk = (
+ None
+ for key, item in iterator(obj)
+ if callit(iteratee, accumulator, item, key, obj, argcount=argcount) is False
+ )
+ next(walk, None)
+
+ return accumulator
+
+
+@t.overload
+def update(
+ obj: t.Dict[t.Any, T2],
+ path: PathT,
+ updater: t.Callable[[T2], t.Any],
+) -> t.Dict[t.Any, t.Any]: ...
+
+
+@t.overload
+def update(
+ obj: t.List[T],
+ path: PathT,
+ updater: t.Callable[[T], t.Any],
+) -> t.List[t.Any]: ...
+
+
+@t.overload
+def update(
+ obj: T,
+ path: PathT,
+ updater: t.Callable[..., t.Any],
+) -> T: ...
+
+
+def update(obj, path, updater):
+ """
+ This method is like :func:`set_` except that accepts updater to produce the value to set. Use
+ :func:`update_with` to customize path creation. The updater is invoked with one argument:
+ ``(value)``.
+
+ Args:
+ obj: Object to modify.
+ path: A string or list of keys that describe the object path to modify.
+ updater: Function that returns updated value.
+
+ Returns:
+ Updated `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> update({}, ["a", "b"], lambda value: value)
+ {'a': {'b': None}}
+ >>> update([], [0, 0], lambda value: 1)
+ [[1]]
+
+ .. versionadded:: 4.0.0
+ """
+ return update_with(obj, path, updater)
+
+
+@t.overload
+def update_with(
+ obj: t.Dict[t.Any, T2],
+ path: PathT,
+ updater: t.Callable[[T2], t.Any],
+ customizer: t.Union[t.Callable[..., t.Any], None],
+) -> t.Dict[t.Any, t.Any]: ...
+
+
+@t.overload
+def update_with(
+ obj: t.List[T],
+ path: PathT,
+ updater: t.Callable[[T], t.Any],
+ customizer: t.Union[t.Callable[..., t.Any], None] = None,
+) -> t.List[t.Any]: ...
+
+
+@t.overload
+def update_with(
+ obj: T,
+ path: PathT,
+ updater: t.Callable[..., t.Any],
+ customizer: t.Union[t.Callable[..., t.Any], None] = None,
+) -> T: ...
+
+
+def update_with(obj, path, updater, customizer=None): # noqa: PLR0912
+ """
+ This method is like :func:`update` except that it accepts customizer which is invoked to produce
+ the objects of path. If customizer returns ``None``, path creation is handled by the method
+ instead. The customizer is invoked with three arguments: ``(nested_value, key, nested_object)``.
+
+ Args:
+ obj: Object to modify.
+ path: A string or list of keys that describe the object path to modify.
+ updater: Function that returns updated value.
+ customizer: The function to customize assigned values.
+
+ Returns:
+ Updated `obj`.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> update_with({}, "[0][1]", lambda: "a", lambda: {})
+ {0: {1: 'a'}}
+
+ .. versionadded:: 4.0.0
+ """
+ if not callable(updater):
+ updater = pyd.constant(updater)
+
+ if customizer is not None and not callable(customizer):
+ call_customizer = partial(callit, clone, customizer, argcount=1)
+ elif customizer:
+ call_customizer = partial(callit, customizer, argcount=getargcount(customizer, maxargs=3))
+ else:
+ call_customizer = None
+
+ default_type = dict if isinstance(obj, dict) else list
+ tokens = to_path_tokens(path)
+
+ last_key = pyd.last(tokens)
+
+ if isinstance(last_key, PathToken):
+ last_key = last_key.key
+
+ target = obj
+
+ for idx, token in enumerate(pyd.initial(tokens)):
+ key = token.key
+ default_factory = pyd.get(tokens, [idx + 1, "default_factory"], default=default_type)
+
+ obj_val = base_get(target, key, default=None)
+ path_obj = None
+
+ if call_customizer:
+ path_obj = call_customizer(obj_val, key, target)
+
+ if path_obj is None:
+ path_obj = default_factory()
+
+ base_set(target, key, path_obj, allow_override=False)
+
+ try:
+ target = base_get(target, key, default=None)
+ except TypeError as exc: # pragma: no cover
+ try:
+ target = target[int(key)]
+ _failed = False
+ except Exception:
+ _failed = True
+
+ if _failed:
+ raise TypeError(f"Unable to update object at index {key!r}. {exc}") from exc
+
+ value = base_get(target, last_key, default=None)
+ base_set(target, last_key, callit(updater, value))
+
+ return obj
+
+
+def unset(obj: t.Union[t.List[t.Any], t.Dict[t.Any, t.Any]], path: PathT) -> bool: # noqa: C901
+ """
+ Removes the property at `path` of `obj`.
+
+ Note:
+ Only ``list``, ``dict``, or objects with a ``pop()`` method can be unset by this function.
+
+ Args:
+ obj: The object to modify.
+ path: The path of the property to unset.
+
+ Returns:
+ Whether the property was deleted.
+
+ Warning:
+ `obj` is modified in place.
+
+ Example:
+
+ >>> obj = {"a": [{"b": {"c": 7}}]}
+ >>> unset(obj, "a[0].b.c")
+ True
+ >>> obj
+ {'a': [{'b': {}}]}
+ >>> unset(obj, "a[0].b.c")
+ False
+ """
+ tokens = to_path_tokens(path)
+
+ last_key = pyd.last(tokens)
+
+ if isinstance(last_key, PathToken):
+ last_key = last_key.key
+
+ target = obj
+
+ for token in pyd.initial(tokens):
+ key = token.key
+
+ try:
+ try:
+ target = target[key]
+ except TypeError:
+ target = target[int(key)]
+ except Exception:
+ # Allow different types reassignment
+ target = UNSET # type: ignore
+
+ if target is UNSET:
+ break
+
+ did_unset = False
+
+ if target is not UNSET:
+ try:
+ try:
+ # last_key can be a lot of things
+ # safe as everything wrapped in try/except
+ target.pop(last_key) # type: ignore
+ did_unset = True
+ except TypeError:
+ target.pop(int(last_key)) # type: ignore
+ did_unset = True
+ except Exception:
+ pass
+
+ return did_unset
+
+
+@t.overload
+def values(obj: t.Mapping[t.Any, T2]) -> t.List[T2]: ...
+
+
+@t.overload
+def values(obj: t.Iterable[T]) -> t.List[T]: ...
+
+
+@t.overload
+def values(obj: t.Any) -> t.List[t.Any]: ...
+
+
+def values(obj):
+ """
+ Creates a list composed of the values of `obj`.
+
+ Args:
+ obj: Object to extract values from.
+
+ Returns:
+ List of values.
+
+ Example:
+
+ >>> results = values({"a": 1, "b": 2, "c": 3})
+ >>> set(results) == set([1, 2, 3])
+ True
+ >>> values([2, 4, 6, 8])
+ [2, 4, 6, 8]
+
+ .. versionadded:: 1.0.0
+
+ .. versionchanged:: 1.1.0
+ Added ``values_in`` as alias.
+
+ .. versionchanged:: 4.0.0
+ Removed alias ``values_in``.
+ """
+ return [value for _, value in iterator(obj)]
+
+
+#
+# Utility methods not a part of the main API
+#
+
+
+def base_clone(value, is_deep=False, customizer=None, key=None, _cloned=False):
+ """Base clone function that supports deep clone and customizer callback."""
+ clone_by = copy.deepcopy if is_deep else copy.copy
+ result = None
+
+ if callable(customizer) and not _cloned:
+ argcount = getargcount(customizer, maxargs=4)
+ cbk = partial(callit, customizer, argcount=argcount)
+ elif _cloned:
+ cbk = customizer
+ else:
+ cbk = None
+
+ if cbk:
+ result = cbk(value, key, value)
+
+ if result is not None:
+ return result
+
+ if not _cloned:
+ result = clone_by(value)
+ else:
+ result = value
+
+ if cbk and not pyd.is_string(value) and not isinstance(value, bytes):
+ for key, subvalue in iterator(value): # noqa: PLR1704
+ if is_deep:
+ val = base_clone(subvalue, is_deep, cbk, key, _cloned=True)
+ else:
+ val = cbk(subvalue, key, value)
+
+ if val is not None:
+ result[key] = val
+
+ return result