dpath-maintainers/dpath-python

[bug] AttributeError: 'tuple' object has no attribute 'extend'

Opened this issue · 0 comments

When using dpath.merge(x, y) with objects as described below, dpath raises an error when it stumbles into a tuple and appears to treat it like a list and uses extend:

import dpath

x = { "foo": [] }
y = { "foo": [("bar", "baz")] }

dpath.merge(x, y)
❯ python3.12
Python 3.12.1 (main, Dec  7 2023, 20:45:44) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dpath
>>> 
>>> x = { "foo": [] }
>>> y = { "foo": [("bar", "baz")] }
>>> 
>>> dpath.merge(x, y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.1/lib/python3.12/site-packages/dpath/__init__.py", line 279, in merge
    filtered_src = search(src, '**', afilter=afilter, separator='/')
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.1/lib/python3.12/site-packages/dpath/__init__.py", line 245, in search
    return segments.fold(obj, f, {})
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.1/lib/python3.12/site-packages/dpath/segments.py", line 393, in fold
    if f(obj, pair, acc) is False:
       ^^^^^^^^^^^^^^^^^
  File "/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.1/lib/python3.12/site-packages/dpath/__init__.py", line 243, in f
    segments.set(result, path, found, hints=segments.types(obj, path))
  File "/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.1/lib/python3.12/site-packages/dpath/segments.py", line 371, in set
    extend(current, last_segment)
  File "/home/linuxbrew/.linuxbrew/Cellar/python@3.12/3.12.1/lib/python3.12/site-packages/dpath/segments.py", line 275, in extend
    thing.extend(expansion)
    ^^^^^^^^^^^^
AttributeError: 'tuple' object has no attribute 'extend'
>>> 

I believe that this can be handled by catching the AttributeError that is raised:

def extend(thing: MutableSequence, index: int, value=None):
"""
Extend a sequence like thing such that it contains at least index +
1 many elements. The extension values will be None (default).
extend(thing, int) -> [thing..., None, ...]
"""
try:
expansion = type(thing)()
# Using this rather than the multiply notation in order to support a
# wider variety of sequence like things.
extra = (index + 1) - len(thing)
for i in range(extra):
expansion += [value]
thing.extend(expansion)
except TypeError:
# We attempted to extend something that doesn't support it. In
# this case we assume thing is actually more like a dictionary
# and doesn't need to be extended.
pass
return thing