Skip to content

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

@lhriley

Description

@lhriley

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions