Skip to content

Commit

Permalink
Support matches-style callbacks on non-dictionary objects that are co…
Browse files Browse the repository at this point in the history
…mpatible with pydash.get().

Refs #168
  • Loading branch information
dgilland committed Sep 28, 2021
1 parent 728bfba commit ca89cde
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -4,6 +4,8 @@ Changelog
=========


- Support matches-style callbacks on non-dictionary objects that are compatible with ``pydash.get`` in functions like ``pydash.find``.

v5.0.2 (2021-07-15)
-------------------

Expand Down
2 changes: 1 addition & 1 deletion src/pydash/helpers.py
Expand Up @@ -102,7 +102,7 @@ def iteriteratee(obj, iteratee=None, reverse=False):

def iterator(obj):
"""Return iterative based on object type."""
if isinstance(obj, dict):
if isinstance(obj, Mapping):
return obj.items()
elif hasattr(obj, "iteritems"):
return obj.iteritems() # noqa: B301
Expand Down
15 changes: 5 additions & 10 deletions src/pydash/predicates.py
Expand Up @@ -4,6 +4,7 @@
.. versionadded:: 2.0.0
"""

from collections.abc import Iterable, Mapping
import datetime
from itertools import islice
import json
Expand All @@ -13,7 +14,7 @@

import pydash as pyd

from .helpers import BUILTINS, NUMBER_TYPES, UNSET, callit, iterator
from .helpers import BUILTINS, NUMBER_TYPES, UNSET, base_get, callit, iterator


__all__ = (
Expand Down Expand Up @@ -914,22 +915,16 @@ def cbk(obj_value, src_value):
else:
cbk = customizer

if (
isinstance(obj, dict)
and isinstance(source, dict)
or isinstance(obj, list)
and isinstance(source, list)
or isinstance(obj, tuple)
and isinstance(source, tuple)
):
if isinstance(source, (Mapping, Iterable)) and not isinstance(source, str):
# Set equal to True if source is empty, otherwise, False and then allow deep comparison to
# determine equality.
equal = not source

# Walk a/b to determine equality.
for key, value in iterator(source):
try:
equal = is_match_with(obj[key], value, cbk, _key=key, _obj=_obj, _source=_source)
obj_value = base_get(obj, key)
equal = is_match_with(obj_value, value, cbk, _key=key, _obj=_obj, _source=_source)
except Exception:
equal = False

Expand Down
12 changes: 12 additions & 0 deletions tests/test_collections.py
@@ -1,3 +1,4 @@
from collections import namedtuple
import math
from operator import itemgetter

Expand Down Expand Up @@ -138,6 +139,17 @@ def test_find(case, expected):
assert _.find(*case) == expected


def test_find_class_object():
obj = fixtures.Object(a=1, b=2)
assert _.find([None, {}, obj], {"b": 2}) == obj


def test_find_namedtuple():
User = namedtuple("User", ["first_name", "last_name"])
obj = User(first_name="Bob", last_name="Smith")
assert _.find([None, {}, obj], {"first_name": "Bob"}) == obj


@parametrize(
"case,expected",
[(({"abc": 1, "xyz": 2, "c": 3}.values(), fixtures.Filter(lambda x: x < 2)), 1)],
Expand Down

0 comments on commit ca89cde

Please sign in to comment.