jmespath.py icon indicating copy to clipboard operation
jmespath.py copied to clipboard

Different behavior on merge function between the JS lib and the Python lib

Open LiveDevLiberate opened this issue 1 year ago • 1 comments

Hi

Environment: Python 3.11.9 + pip 24.3.1 LIbrary: jmespath 1.0.1

I'm trying to use jmespath to extract some fields from the JSON file. But I got differnt results from the JS library and Python library. test.json

merge(
    {
        type: type,
        id: id_str
    },
    modules.module_dynamic.{
        title: major.opus.title || archive.title || `发布了动态`,
        desc:  major.opus.summary.text || major.archive.desc,
        covers: major.opus.pics[].url[] || major.archive.covers[]
    },
    orig.modules.module_dynamic.{
        title: major.opus.title || archive.title || `转发了动态`,
        desc:  major.opus.summary.text || major.archive.desc,
        covers: major.opus.pics[].url[] || major.archive.covers[]
    },
    modules.module_author.{
        time: pub_ts
    },
    modules.module_stat.{
        stat: {
            like: like.count,
            comment: comment.count,
            forward: forward.count
        }
    }
)

It's ok, when I use jmespath playground. image

But when I use the python lib, I got this type error. Looks likes the python library don't merge none values in the merge function.

.venv/lib/python3.11/site-packages/jmespath/__init__.py:12: in search
    return parser.Parser().parse(expression).search(data, options=options)
.venv/lib/python3.11/site-packages/jmespath/parser.py:509: in search
    result = interpreter.visit(self.parsed, value)
.venv/lib/python3.11/site-packages/jmespath/visitor.py:94: in visit
    return method(node, *args, **kwargs)
.venv/lib/python3.11/site-packages/jmespath/visitor.py:171: in visit_function_expression
    return self._functions.call_function(node['value'], resolved_args)
.venv/lib/python3.11/site-packages/jmespath/functions.py:81: in call_function
    return function(self, *resolved_args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <jmespath.functions.Functions object at 0x7f4fc11dae90>
arguments = ({'id': '1000725331289571330', 'type': 'DYNAMIC_TYPE_DRAW'}, {'covers': ['http://i0.hdslb.com/bfs/new_dyn/10686e544526...greatest evil.', 'title': '发布了动态'}, None, {'time': 1731837923}, {'stat': {'comment': 276, 'forward': 5, 'like': 1784}})
merged = {'covers': ['http://i0.hdslb.com/bfs/new_dyn/10686e544526539b0da871b41339d83a389245745.png'], 'desc': '第六集又双叒叕看爽了[脱单do...s us to our greatest good is also the cause of our greatest evil.', 'id': '1000725331289571330', 'title': '发 布了动态', ...}
arg = None

    @signature({"types": ["object"], "variadic": True})
    def _func_merge(self, *arguments):
        merged = {}
        for arg in arguments:
>           merged.update(arg)
E           TypeError: 'NoneType' object is not iterable

.venv/lib/python3.11/site-packages/jmespath/functions.py:266: TypeError

LiveDevLiberate avatar Nov 23 '24 09:11 LiveDevLiberate

You merge() expression has five arguments. The third expression (orig.modules.module_dynamic.{ … }) evaluates to a null JSON value (or NoneType in Python).

From the specification, the merge() function accepts only arguments of object type. Thus, as far as I can tell, the result of your expression SHOULD raise an error.

The fact that the official JS library does not is a non-compliant behaviour in my mind.

springcomp avatar Feb 04 '25 21:02 springcomp