Skip to content

Commit

Permalink
Merge c548717 into 2a2fb8e
Browse files Browse the repository at this point in the history
  • Loading branch information
DeviousStoat committed Jan 27, 2024
2 parents 2a2fb8e + c548717 commit 61ed1a7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 35 deletions.
25 changes: 7 additions & 18 deletions src/pydash/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -2295,9 +2295,6 @@ def update_with(obj, path, updater, customizer=None): # noqa: C901
default_type = dict if isinstance(obj, dict) else list
tokens = to_path_tokens(path)

if not pyd.is_list(tokens): # pragma: no cover
tokens = [tokens]

last_key = pyd.last(tokens)

if isinstance(last_key, PathToken):
Expand All @@ -2306,12 +2303,8 @@ def update_with(obj, path, updater, customizer=None): # noqa: C901
target = obj

for idx, token in enumerate(pyd.initial(tokens)):
if isinstance(token, PathToken):
key = token.key
default_factory = pyd.get(tokens, [idx + 1, "default_factory"], default=default_type)
else:
key = token
default_factory = default_type
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
Expand Down Expand Up @@ -2371,9 +2364,6 @@ def unset(obj: t.Union[t.List, t.Dict], path: PathT) -> bool: # noqa: C901
"""
tokens = to_path_tokens(path)

if not pyd.is_list(tokens): # pragma: no cover
tokens = [tokens]

last_key = pyd.last(tokens)

if isinstance(last_key, PathToken):
Expand All @@ -2382,10 +2372,7 @@ def unset(obj: t.Union[t.List, t.Dict], path: PathT) -> bool: # noqa: C901
target = obj

for token in pyd.initial(tokens):
if isinstance(token, PathToken):
key = token.key
else:
key = token
key = token.key

try:
try:
Expand All @@ -2404,10 +2391,12 @@ def unset(obj: t.Union[t.List, t.Dict], path: PathT) -> bool: # noqa: C901
if target is not UNSET:
try:
try:
target.pop(last_key)
# 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))
target.pop(int(last_key)) # type: ignore
did_unset = True
except Exception:
pass
Expand Down
41 changes: 24 additions & 17 deletions src/pydash/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -1378,13 +1378,7 @@ def to_path(value: PathT) -> t.List[t.Hashable]:
.. versionchanged:: 4.2.1
Ensure returned path is always a list.
"""
tokens = to_path_tokens(value)
if isinstance(tokens, list):
path = [
token.key if isinstance(token, PathToken) else token for token in to_path_tokens(value)
]
else:
path = [tokens]
path = [token.key for token in to_path_tokens(value)]
return path


Expand Down Expand Up @@ -1425,26 +1419,39 @@ def unique_id(prefix: t.Union[str, None] = None) -> str:
#


def to_path_tokens(value):
def _maybe_list_index(key):
if isinstance(key, int):
return key
if pyd.is_string(key) and RE_PATH_LIST_INDEX.match(key):
return int(key[1:-1])
return None


def _to_path_token(key) -> PathToken:
list_index = _maybe_list_index(key)
if list_index is not None:
return PathToken(list_index, default_factory=list)
return PathToken(
unescape_path_key(key) if pyd.is_string(key) else key,
default_factory=dict,
)


def to_path_tokens(value) -> t.List[PathToken]:
"""Parse `value` into :class:`PathToken` objects."""
if pyd.is_string(value) and ("." in value or "[" in value):
# Since we can't tell whether a bare number is supposed to be dict key or a list index, we
# support a special syntax where any string-integer surrounded by brackets is treated as a
# list index and converted to an integer.
keys = [
(
PathToken(int(key[1:-1]), default_factory=list)
if RE_PATH_LIST_INDEX.match(key)
else PathToken(unescape_path_key(key), default_factory=dict)
)
for key in filter(None, RE_PATH_KEY_DELIM.split(value))
]
keys = [_to_path_token(key) for key in filter(None, RE_PATH_KEY_DELIM.split(value))]
elif pyd.is_string(value) or pyd.is_number(value):
keys = [PathToken(value, default_factory=dict)]
elif value is UNSET:
keys = []
elif pyd.is_list(value):
keys = [_to_path_token(key) for key in value]
else:
keys = value
keys = [_to_path_token(value)]

return keys

Expand Down
11 changes: 11 additions & 0 deletions tests/test_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,17 @@ def test_set_(case, expected):
assert _.set_(*case) == expected


def test_set_on_class_works_the_same_with_string_and_list():
class A:
def __init__(self):
self.x = {}

a1 = A()
a2 = A()

assert _.set_(a1, "x.a.b", 1).x == _.set_(a2, ["x", "a", "b"], 1).x


@parametrize(
"case,expected",
[
Expand Down

0 comments on commit 61ed1a7

Please sign in to comment.