[Git][debian-gis-team/jsonpath-ng][upstream] New upstream version 1.7.0
Antonio Valentino (@antonio.valentino)
gitlab at salsa.debian.org
Sun Oct 13 18:35:05 BST 2024
Antonio Valentino pushed to branch upstream at Debian GIS Project / jsonpath-ng
Commits:
0f47a929 by Antonio Valentino at 2024-10-13T17:26:19+00:00
New upstream version 1.7.0
- - - - -
16 changed files:
- PKG-INFO
- README.rst
- jsonpath_ng.egg-info/PKG-INFO
- jsonpath_ng.egg-info/entry_points.txt
- jsonpath_ng/__init__.py
- jsonpath_ng/ext/iterable.py
- jsonpath_ng/ext/parser.py
- jsonpath_ng/ext/string.py
- jsonpath_ng/jsonpath.py
- jsonpath_ng/lexer.py
- jsonpath_ng/parser.py
- setup.py
- tests/test_jsonpath.py
- tests/test_jsonpath_rw_ext.py
- tests/test_lexer.py
- tests/test_parser.py
Changes:
=====================================
PKG-INFO
=====================================
@@ -1,378 +1,381 @@
-Metadata-Version: 2.1
+Metadata-Version: 1.1
Name: jsonpath-ng
-Version: 1.6.1
+Version: 1.7.0
Summary: A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming.
Home-page: https://github.com/h2non/jsonpath-ng
Author: Tomas Aparicio
Author-email: tomas at aparicio.me
License: Apache 2.0
+Description: Python JSONPath Next-Generation |Build Status| |PyPI|
+ =====================================================
+
+ A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic
+ and binary comparison operators, as defined in the original `JSONPath proposal`_.
+
+ This packages merges both `jsonpath-rw`_ and `jsonpath-rw-ext`_ and
+ provides several AST API enhancements, such as the ability to update or remove nodes in the tree.
+
+ About
+ -----
+
+ This library provides a robust and significantly extended implementation
+ of JSONPath for Python. It is tested with CPython 3.8 and higher.
+
+ This library differs from other JSONPath implementations in that it is a
+ full *language* implementation, meaning the JSONPath expressions are
+ first class objects, easy to analyze, transform, parse, print, and
+ extend.
+
+ Quick Start
+ -----------
+
+ To install, use pip:
+
+ .. code:: bash
+
+ $ pip install --upgrade jsonpath-ng
+
+
+ Usage
+ -----
+
+ Basic examples:
+
+ .. code:: python
+
+ $ python
+
+ >>> from jsonpath_ng import jsonpath, parse
+
+ # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
+ >>> jsonpath_expr = parse('foo[*].baz')
+
+ # Extracting values is easy
+ >>> [match.value for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
+ [1, 2]
+
+ # Matches remember where they came from
+ >>> [str(match.full_path) for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
+ ['foo.[0].baz', 'foo.[1].baz']
+
+ # Modifying values matching the path
+ >>> jsonpath_expr.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
+ {'foo': [{'baz': 3}, {'baz': 3}]}
+
+ # Modifying one of the values matching the path
+ >>> matches = jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})
+ >>> matches[0].full_path.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
+ {'foo': [{'baz': 3}, {'baz': 2}]}
+
+ # Removing all values matching a path
+ >>> jsonpath_expr.filter(lambda d: True, {'foo': [{'baz': 1}, {'baz': 2}]})
+ {'foo': [{}, {}]}
+
+ # Removing values containing particular data matching path
+ >>> jsonpath_expr.filter(lambda d: d == 2, {'foo': [{'baz': 1}, {'baz': 2}]})
+ {'foo': [{'baz': 1}, {}]}
+
+ # And this can be useful for automatically providing ids for bits of data that do not have them (currently a global switch)
+ >>> jsonpath.auto_id_field = 'id'
+ >>> [match.value for match in parse('foo[*].id').find({'foo': [{'id': 'bizzle'}, {'baz': 3}]})]
+ ['foo.bizzle', 'foo.[1]']
+
+ # A handy extension: named operators like `parent`
+ >>> [match.value for match in parse('a.*.b.`parent`.c').find({'a': {'x': {'b': 1, 'c': 'number one'}, 'y': {'b': 2, 'c': 'number two'}}})]
+ ['number two', 'number one']
+
+ # You can also build expressions directly quite easily
+ >>> from jsonpath_ng.jsonpath import Fields
+ >>> from jsonpath_ng.jsonpath import Slice
+
+ >>> jsonpath_expr_direct = Fields('foo').child(Slice('*')).child(Fields('baz')) # This is equivalent
+
+
+ Using the extended parser:
+
+ .. code:: python
+
+ $ python
+
+ >>> from jsonpath_ng.ext import parse
+
+ # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
+ >>> jsonpath_expr = parse('foo[*].baz')
+
+
+ JSONPath Syntax
+ ---------------
+
+ The JSONPath syntax supported by this library includes some additional
+ features and omits some problematic features (those that make it
+ unportable). In particular, some new operators such as ``|`` and
+ ``where`` are available, and parentheses are used for grouping not for
+ callbacks into Python, since with these changes the language is not
+ trivially associative. Also, fields may be quoted whether or not they
+ are contained in brackets.
+
+ Atomic expressions:
+
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +=======================+=============================================================================================+
+ | ``$`` | The root object |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ```this``` | The "current" object. |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ```foo``` | More generally, this syntax allows "named operators" to extend JSONPath is arbitrary ways |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | *field* | Specified field(s), described below |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ``[`` *field* ``]`` | Same as *field* |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ``[`` *idx* ``]`` | Array access, described below (this is always unambiguous with field access) |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+
+ Jsonpath operators:
+
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +======================================+===================================================================================+
+ | *jsonpath1* ``.`` *jsonpath2* | All nodes matched by *jsonpath2* starting at any node matching *jsonpath1* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath* ``[`` *whatever* ``]`` | Same as *jsonpath*\ ``.``\ *whatever* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``..`` *jsonpath2* | All nodes matched by *jsonpath2* that descend from any node matching *jsonpath1* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``where`` *jsonpath2* | Any nodes matching *jsonpath1* with a child matching *jsonpath2* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``wherenot`` *jsonpath2* | Any nodes matching *jsonpath1* with a child not matching *jsonpath2* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``|`` *jsonpath2* | Any nodes matching the union of *jsonpath1* and *jsonpath2* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+
+ Field specifiers ( *field* ):
+
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +=========================+=====================================================================================+
+ | ``fieldname`` | the field ``fieldname`` (from the "current" object) |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | ``"fieldname"`` | same as above, for allowing special characters in the fieldname |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | ``'fieldname'`` | ditto |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | ``*`` | any field |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | *field* ``,`` *field* | either of the named fields (you can always build equivalent jsonpath using ``|``) |
+ +-------------------------+-------------------------------------------------------------------------------------+
+
+ Array specifiers ( *idx* ):
+
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +=========================================+=======================================================================================+
+ | ``[``\ *n*\ ``]`` | array index (may be comma-separated list) |
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+ | ``[``\ *start*\ ``?:``\ *end*\ ``?]`` | array slicing (note that *step* is unimplemented only due to lack of need thus far) |
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+ | ``[*]`` | any array index |
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+
+ Programmatic JSONPath
+ ---------------------
+
+ If you are programming in Python and would like a more robust way to
+ create JSONPath expressions that does not depend on a parser, it is very
+ easy to do so directly, and here are some examples:
+
+ - ``Root()``
+ - ``Slice(start=0, end=None, step=None)``
+ - ``Fields('foo', 'bar')``
+ - ``Index(42)``
+ - ``Child(Fields('foo'), Index(42))``
+ - ``Where(Slice(), Fields('subfield'))``
+ - ``Descendants(jsonpath, jsonpath)``
+
+
+ Extras
+ ------
+
+ - *Path data*: The result of ``JsonPath.find`` provide detailed context
+ and path data so it is easy to traverse to parent objects, print full
+ paths to pieces of data, and generate automatic ids.
+ - *Automatic Ids*: If you set ``jsonpath_ng.auto_id_field`` to a value
+ other than None, then for any piece of data missing that field, it
+ will be replaced by the JSONPath to it, giving automatic unique ids
+ to any piece of data. These ids will take into account any ids
+ already present as well.
+ - *Named operators*: Instead of using ``@`` to reference the current
+ object, this library uses ```this```. In general, any string
+ contained in backquotes can be made to be a new operator, currently
+ by extending the library.
+
+
+ Extensions
+ ----------
+
+ To use the extensions below you must import from `jsonpath_ng.ext`.
+
+ +--------------+-----------------------------------------------+
+ | name | Example |
+ +==============+===============================================+
+ | len | - ``$.objects.`len``` |
+ +--------------+-----------------------------------------------+
+ | sub | - ``$.field.`sub(/foo\\\\+(.*)/, \\\\1)``` |
+ | | - ``$.field.`sub(/regex/, replacement)``` |
+ +--------------+-----------------------------------------------+
+ | split | - ``$.field.`split(+, 2, -1)``` |
+ | | - ``$.field.`split(",", *, -1)``` |
+ | | - ``$.field.`split(' ', -1, -1)``` |
+ | | - ``$.field.`split(sep, segement, maxsplit)```|
+ +--------------+-----------------------------------------------+
+ | sorted | - ``$.objects.`sorted``` |
+ | | - ``$.objects[\\some_field]`` |
+ | | - ``$.objects[\\some_field,/other_field]`` |
+ +--------------+-----------------------------------------------+
+ | filter | - ``$.objects[?(@some_field > 5)]`` |
+ | | - ``$.objects[?some_field = "foobar"]`` |
+ | | - ``$.objects[?some_field =~ "foobar"]`` |
+ | | - ``$.objects[?some_field > 5 & other < 2]`` |
+ | | |
+ | | Supported operators: |
+ | | - Equality: ==, =, != |
+ | | - Comparison: >, >=, <, <= |
+ | | - Regex match: =~ |
+ | | |
+ | | Combine multiple criteria with '&'. |
+ | | |
+ | | Properties can only be compared to static |
+ | | values. |
+ +--------------+-----------------------------------------------+
+ | arithmetic | - ``$.foo + "_" + $.bar`` |
+ | (-+*/) | - ``$.foo * 12`` |
+ | | - ``$.objects[*].cow + $.objects[*].cat`` |
+ +--------------+-----------------------------------------------+
+
+ About arithmetic and string
+ ---------------------------
+
+ Operations are done with python operators and allows types that python
+ allows, and return [] if the operation can be done due to incompatible types.
+
+ When operators are used, a jsonpath must be be fully defined otherwise
+ jsonpath-rw-ext can't known if the expression is a string or a jsonpath field,
+ in this case it will choice string as type.
+
+ Example with data::
+
+ {
+ 'cow': 'foo',
+ 'fish': 'bar'
+ }
+
+ | ``cow + fish`` returns ``cowfish``
+ | ``$.cow + $.fish`` returns ``foobar``
+ | ``$.cow + "_" + $.fish`` returns ``foo_bar``
+ | ``$.cow + "_" + fish`` returns ``foo_fish``
+
+ About arithmetic and list
+ -------------------------
+
+ Arithmetic can be used against two lists if they have the same size.
+
+ Example with data::
+
+ {'objects': [
+ {'cow': 2, 'cat': 3},
+ {'cow': 4, 'cat': 6}
+ ]}
+
+ | ``$.objects[\*].cow + $.objects[\*].cat`` returns ``[6, 9]``
+
+ More to explore
+ ---------------
+
+ There are way too many JSONPath implementations out there to discuss.
+ Some are robust, some are toy projects that still work fine, some are
+ exercises. There will undoubtedly be many more. This one is made for use
+ in released, maintained code, and in particular for programmatic access
+ to the abstract syntax and extension. But JSONPath at its simplest just
+ isn't that complicated, so you can probably use any of them
+ successfully. Why not this one?
+
+ The original proposal, as far as I know:
+
+ - `JSONPath - XPath for
+ JSON <http://goessner.net/articles/JSONPath/>`__ by Stefan Goessner.
+
+ Other examples
+ --------------
+
+ Loading json data from file
+
+ .. code:: python
+
+ import json
+ d = json.loads('{"foo": [{"baz": 1}, {"baz": 2}]}')
+ # or
+ with open('myfile.json') as f:
+ d = json.load(f)
+
+ Special note about PLY and docstrings
+ -------------------------------------
+
+ The main parsing toolkit underlying this library,
+ `PLY <https://github.com/dabeaz/ply>`__, does not work with docstrings
+ removed. For example, ``PYTHONOPTIMIZE=2`` and ``python -OO`` will both
+ cause a failure.
+
+ Contributors
+ ------------
+
+ This package is authored and maintained by:
+
+ - `Kenn Knowles <https://github.com/kennknowles>`__
+ (`@kennknowles <https://twitter.com/KennKnowles>`__)
+ - `Tomas Aparicio <https://github.com/h2non>`
+
+ with the help of patches submitted by `these contributors <https://github.com/kennknowles/python-jsonpath-ng/graphs/contributors>`__.
+
+ Copyright and License
+ ---------------------
+
+ Copyright 2013 - Kenneth Knowles
+
+ Copyright 2017 - Tomas Aparicio
+
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
+ not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+
+ ::
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ .. _`JSONPath proposal`: http://goessner.net/articles/JsonPath/
+ .. _`jsonpath-rw`: https://github.com/kennknowles/python-jsonpath-rw
+ .. _`jsonpath-rw-ext`: https://pypi.python.org/pypi/jsonpath-rw-ext/
+
+ .. |PyPi downloads| image:: https://pypip.in/d/jsonpath-ng/badge.png
+ :target: https://pypi.python.org/pypi/jsonpath-ng
+ .. |Build Status| image:: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml/badge.svg
+ :target: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml
+ .. |PyPI| image:: https://img.shields.io/pypi/v/jsonpath-ng.svg?maxAge=2592000?style=flat-square
+ :target: https://pypi.python.org/pypi/jsonpath-ng
+
+Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
-License-File: LICENSE
-
-Python JSONPath Next-Generation |Build Status| |PyPI|
-=====================================================
-
-A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic
-and binary comparison operators, as defined in the original `JSONPath proposal`_.
-
-This packages merges both `jsonpath-rw`_ and `jsonpath-rw-ext`_ and
-provides several AST API enhancements, such as the ability to update or remove nodes in the tree.
-
-About
------
-
-This library provides a robust and significantly extended implementation
-of JSONPath for Python. It is tested with CPython 3.7 and higher.
-
-This library differs from other JSONPath implementations in that it is a
-full *language* implementation, meaning the JSONPath expressions are
-first class objects, easy to analyze, transform, parse, print, and
-extend.
-
-Quick Start
------------
-
-To install, use pip:
-
-.. code:: bash
-
- $ pip install --upgrade jsonpath-ng
-
-
-Usage
------
-
-Basic examples:
-
-.. code:: python
-
- $ python
-
- >>> from jsonpath_ng import jsonpath, parse
-
- # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
- >>> jsonpath_expr = parse('foo[*].baz')
-
- # Extracting values is easy
- >>> [match.value for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
- [1, 2]
-
- # Matches remember where they came from
- >>> [str(match.full_path) for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
- ['foo.[0].baz', 'foo.[1].baz']
-
- # Modifying values matching the path
- >>> jsonpath_expr.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
- {'foo': [{'baz': 3}, {'baz': 3}]}
-
- # Modifying one of the values matching the path
- >>> matches = jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})
- >>> matches[0].full_path.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
- {'foo': [{'baz': 3}, {'baz': 2}]}
-
- # Removing all values matching a path
- >>> jsonpath_expr.filter(lambda d: True, {'foo': [{'baz': 1}, {'baz': 2}]})
- {'foo': [{}, {}]}
-
- # Removing values containing particular data matching path
- >>> jsonpath_expr.filter(lambda d: d == 2, {'foo': [{'baz': 1}, {'baz': 2}]})
- {'foo': [{'baz': 1}, {}]}
-
- # And this can be useful for automatically providing ids for bits of data that do not have them (currently a global switch)
- >>> jsonpath.auto_id_field = 'id'
- >>> [match.value for match in parse('foo[*].id').find({'foo': [{'id': 'bizzle'}, {'baz': 3}]})]
- ['foo.bizzle', 'foo.[1]']
-
- # A handy extension: named operators like `parent`
- >>> [match.value for match in parse('a.*.b.`parent`.c').find({'a': {'x': {'b': 1, 'c': 'number one'}, 'y': {'b': 2, 'c': 'number two'}}})]
- ['number two', 'number one']
-
- # You can also build expressions directly quite easily
- >>> from jsonpath_ng.jsonpath import Fields
- >>> from jsonpath_ng.jsonpath import Slice
-
- >>> jsonpath_expr_direct = Fields('foo').child(Slice('*')).child(Fields('baz')) # This is equivalent
-
-
-Using the extended parser:
-
-.. code:: python
-
- $ python
-
- >>> from jsonpath_ng.ext import parse
-
- # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
- >>> jsonpath_expr = parse('foo[*].baz')
-
-
-JSONPath Syntax
----------------
-
-The JSONPath syntax supported by this library includes some additional
-features and omits some problematic features (those that make it
-unportable). In particular, some new operators such as ``|`` and
-``where`` are available, and parentheses are used for grouping not for
-callbacks into Python, since with these changes the language is not
-trivially associative. Also, fields may be quoted whether or not they
-are contained in brackets.
-
-Atomic expressions:
-
-+-----------------------+---------------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=======================+=============================================================================================+
-| ``$`` | The root object |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ```this``` | The "current" object. |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ```foo``` | More generally, this syntax allows "named operators" to extend JSONPath is arbitrary ways |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| *field* | Specified field(s), described below |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ``[`` *field* ``]`` | Same as *field* |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ``[`` *idx* ``]`` | Array access, described below (this is always unambiguous with field access) |
-+-----------------------+---------------------------------------------------------------------------------------------+
-
-Jsonpath operators:
-
-+-------------------------------------+------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=====================================+====================================================================================+
-| *jsonpath1* ``.`` *jsonpath2* | All nodes matched by *jsonpath2* starting at any node matching *jsonpath1* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath* ``[`` *whatever* ``]`` | Same as *jsonpath*\ ``.``\ *whatever* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``..`` *jsonpath2* | All nodes matched by *jsonpath2* that descend from any node matching *jsonpath1* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``where`` *jsonpath2* | Any nodes matching *jsonpath1* with a child matching *jsonpath2* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``|`` *jsonpath2* | Any nodes matching the union of *jsonpath1* and *jsonpath2* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-
-Field specifiers ( *field* ):
-
-+-------------------------+-------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=========================+=====================================================================================+
-| ``fieldname`` | the field ``fieldname`` (from the "current" object) |
-+-------------------------+-------------------------------------------------------------------------------------+
-| ``"fieldname"`` | same as above, for allowing special characters in the fieldname |
-+-------------------------+-------------------------------------------------------------------------------------+
-| ``'fieldname'`` | ditto |
-+-------------------------+-------------------------------------------------------------------------------------+
-| ``*`` | any field |
-+-------------------------+-------------------------------------------------------------------------------------+
-| *field* ``,`` *field* | either of the named fields (you can always build equivalent jsonpath using ``|``) |
-+-------------------------+-------------------------------------------------------------------------------------+
-
-Array specifiers ( *idx* ):
-
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=========================================+=======================================================================================+
-| ``[``\ *n*\ ``]`` | array index (may be comma-separated list) |
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-| ``[``\ *start*\ ``?:``\ *end*\ ``?]`` | array slicing (note that *step* is unimplemented only due to lack of need thus far) |
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-| ``[*]`` | any array index |
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-
-Programmatic JSONPath
----------------------
-
-If you are programming in Python and would like a more robust way to
-create JSONPath expressions that does not depend on a parser, it is very
-easy to do so directly, and here are some examples:
-
-- ``Root()``
-- ``Slice(start=0, end=None, step=None)``
-- ``Fields('foo', 'bar')``
-- ``Index(42)``
-- ``Child(Fields('foo'), Index(42))``
-- ``Where(Slice(), Fields('subfield'))``
-- ``Descendants(jsonpath, jsonpath)``
-
-
-Extras
-------
-
-- *Path data*: The result of ``JsonPath.find`` provide detailed context
- and path data so it is easy to traverse to parent objects, print full
- paths to pieces of data, and generate automatic ids.
-- *Automatic Ids*: If you set ``jsonpath_ng.auto_id_field`` to a value
- other than None, then for any piece of data missing that field, it
- will be replaced by the JSONPath to it, giving automatic unique ids
- to any piece of data. These ids will take into account any ids
- already present as well.
-- *Named operators*: Instead of using ``@`` to reference the current
- object, this library uses ```this```. In general, any string
- contained in backquotes can be made to be a new operator, currently
- by extending the library.
-
-
-Extensions
-----------
-
-To use the extensions below you must import from `jsonpath_ng.ext`.
-
-+--------------+-----------------------------------------------+
-| name | Example |
-+==============+===============================================+
-| len | - ``$.objects.`len``` |
-+--------------+-----------------------------------------------+
-| sub | - ``$.field.`sub(/foo\\\\+(.*)/, \\\\1)``` |
-| | - ``$.field.`sub(/regex/, replacement)``` |
-+--------------+-----------------------------------------------+
-| split | - ``$.field.`split(+, 2, -1)``` |
-| | - ``$.field.`split(sep, segement, maxsplit)```|
-+--------------+-----------------------------------------------+
-| sorted | - ``$.objects.`sorted``` |
-| | - ``$.objects[\\some_field]`` |
-| | - ``$.objects[\\some_field,/other_field]`` |
-+--------------+-----------------------------------------------+
-| filter | - ``$.objects[?(@some_field > 5)]`` |
-| | - ``$.objects[?some_field = "foobar"]`` |
-| | - ``$.objects[?some_field =~ "foobar"]`` |
-| | - ``$.objects[?some_field > 5 & other < 2]`` |
-| | |
-| | Supported operators: |
-| | - Equality: ==, =, != |
-| | - Comparison: >, >=, <, <= |
-| | - Regex match: =~ |
-| | |
-| | Combine multiple criteria with '&'. |
-| | |
-| | Properties can only be compared to static |
-| | values. |
-+--------------+-----------------------------------------------+
-| arithmetic | - ``$.foo + "_" + $.bar`` |
-| (-+*/) | - ``$.foo * 12`` |
-| | - ``$.objects[*].cow + $.objects[*].cat`` |
-+--------------+-----------------------------------------------+
-
-About arithmetic and string
----------------------------
-
-Operations are done with python operators and allows types that python
-allows, and return [] if the operation can be done due to incompatible types.
-
-When operators are used, a jsonpath must be be fully defined otherwise
-jsonpath-rw-ext can't known if the expression is a string or a jsonpath field,
-in this case it will choice string as type.
-
-Example with data::
-
- {
- 'cow': 'foo',
- 'fish': 'bar'
- }
-
-| ``cow + fish`` returns ``cowfish``
-| ``$.cow + $.fish`` returns ``foobar``
-| ``$.cow + "_" + $.fish`` returns ``foo_bar``
-| ``$.cow + "_" + fish`` returns ``foo_fish``
-
-About arithmetic and list
--------------------------
-
-Arithmetic can be used against two lists if they have the same size.
-
-Example with data::
-
- {'objects': [
- {'cow': 2, 'cat': 3},
- {'cow': 4, 'cat': 6}
- ]}
-
-| ``$.objects[\*].cow + $.objects[\*].cat`` returns ``[6, 9]``
-
-More to explore
----------------
-
-There are way too many JSONPath implementations out there to discuss.
-Some are robust, some are toy projects that still work fine, some are
-exercises. There will undoubtedly be many more. This one is made for use
-in released, maintained code, and in particular for programmatic access
-to the abstract syntax and extension. But JSONPath at its simplest just
-isn't that complicated, so you can probably use any of them
-successfully. Why not this one?
-
-The original proposal, as far as I know:
-
-- `JSONPath - XPath for
- JSON <http://goessner.net/articles/JSONPath/>`__ by Stefan Goessner.
-
-Other examples
---------------
-
-Loading json data from file
-
-.. code:: python
-
- import json
- d = json.loads('{"foo": [{"baz": 1}, {"baz": 2}]}')
- # or
- with open('myfile.json') as f:
- d = json.load(f)
-
-Special note about PLY and docstrings
--------------------------------------
-
-The main parsing toolkit underlying this library,
-`PLY <https://github.com/dabeaz/ply>`__, does not work with docstrings
-removed. For example, ``PYTHONOPTIMIZE=2`` and ``python -OO`` will both
-cause a failure.
-
-Contributors
-------------
-
-This package is authored and maintained by:
-
-- `Kenn Knowles <https://github.com/kennknowles>`__
- (`@kennknowles <https://twitter.com/KennKnowles>`__)
-- `Tomas Aparicio <https://github.com/h2non>`
-
-with the help of patches submitted by `these contributors <https://github.com/kennknowles/python-jsonpath-ng/graphs/contributors>`__.
-
-Copyright and License
----------------------
-
-Copyright 2013 - Kenneth Knowles
-
-Copyright 2017 - Tomas Aparicio
-
-Licensed under the Apache License, Version 2.0 (the "License"); you may
-not use this file except in compliance with the License. You may obtain
-a copy of the License at
-
-::
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-.. _`JSONPath proposal`: http://goessner.net/articles/JsonPath/
-.. _`jsonpath-rw`: https://github.com/kennknowles/python-jsonpath-rw
-.. _`jsonpath-rw-ext`: https://pypi.python.org/pypi/jsonpath-rw-ext/
-
-.. |PyPi downloads| image:: https://pypip.in/d/jsonpath-ng/badge.png
- :target: https://pypi.python.org/pypi/jsonpath-ng
-.. |Build Status| image:: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml/badge.svg
- :target: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml
-.. |PyPI| image:: https://img.shields.io/pypi/v/jsonpath-ng.svg?maxAge=2592000?style=flat-square
- :target: https://pypi.python.org/pypi/jsonpath-ng
=====================================
README.rst
=====================================
@@ -11,7 +11,7 @@ About
-----
This library provides a robust and significantly extended implementation
-of JSONPath for Python. It is tested with CPython 3.7 and higher.
+of JSONPath for Python. It is tested with CPython 3.8 and higher.
This library differs from other JSONPath implementations in that it is a
full *language* implementation, meaning the JSONPath expressions are
@@ -126,19 +126,21 @@ Atomic expressions:
Jsonpath operators:
-+-------------------------------------+------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=====================================+====================================================================================+
-| *jsonpath1* ``.`` *jsonpath2* | All nodes matched by *jsonpath2* starting at any node matching *jsonpath1* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath* ``[`` *whatever* ``]`` | Same as *jsonpath*\ ``.``\ *whatever* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``..`` *jsonpath2* | All nodes matched by *jsonpath2* that descend from any node matching *jsonpath1* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``where`` *jsonpath2* | Any nodes matching *jsonpath1* with a child matching *jsonpath2* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``|`` *jsonpath2* | Any nodes matching the union of *jsonpath1* and *jsonpath2* |
-+-------------------------------------+------------------------------------------------------------------------------------+
++--------------------------------------+-----------------------------------------------------------------------------------+
+| Syntax | Meaning |
++======================================+===================================================================================+
+| *jsonpath1* ``.`` *jsonpath2* | All nodes matched by *jsonpath2* starting at any node matching *jsonpath1* |
++--------------------------------------+-----------------------------------------------------------------------------------+
+| *jsonpath* ``[`` *whatever* ``]`` | Same as *jsonpath*\ ``.``\ *whatever* |
++--------------------------------------+-----------------------------------------------------------------------------------+
+| *jsonpath1* ``..`` *jsonpath2* | All nodes matched by *jsonpath2* that descend from any node matching *jsonpath1* |
++--------------------------------------+-----------------------------------------------------------------------------------+
+| *jsonpath1* ``where`` *jsonpath2* | Any nodes matching *jsonpath1* with a child matching *jsonpath2* |
++--------------------------------------+-----------------------------------------------------------------------------------+
+| *jsonpath1* ``wherenot`` *jsonpath2* | Any nodes matching *jsonpath1* with a child not matching *jsonpath2* |
++--------------------------------------+-----------------------------------------------------------------------------------+
+| *jsonpath1* ``|`` *jsonpath2* | Any nodes matching the union of *jsonpath1* and *jsonpath2* |
++--------------------------------------+-----------------------------------------------------------------------------------+
Field specifiers ( *field* ):
@@ -215,6 +217,8 @@ To use the extensions below you must import from `jsonpath_ng.ext`.
| | - ``$.field.`sub(/regex/, replacement)``` |
+--------------+-----------------------------------------------+
| split | - ``$.field.`split(+, 2, -1)``` |
+| | - ``$.field.`split(",", *, -1)``` |
+| | - ``$.field.`split(' ', -1, -1)``` |
| | - ``$.field.`split(sep, segement, maxsplit)```|
+--------------+-----------------------------------------------+
| sorted | - ``$.objects.`sorted``` |
=====================================
jsonpath_ng.egg-info/PKG-INFO
=====================================
@@ -1,378 +1,381 @@
-Metadata-Version: 2.1
+Metadata-Version: 1.1
Name: jsonpath-ng
-Version: 1.6.1
+Version: 1.7.0
Summary: A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming.
Home-page: https://github.com/h2non/jsonpath-ng
Author: Tomas Aparicio
Author-email: tomas at aparicio.me
License: Apache 2.0
+Description: Python JSONPath Next-Generation |Build Status| |PyPI|
+ =====================================================
+
+ A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic
+ and binary comparison operators, as defined in the original `JSONPath proposal`_.
+
+ This packages merges both `jsonpath-rw`_ and `jsonpath-rw-ext`_ and
+ provides several AST API enhancements, such as the ability to update or remove nodes in the tree.
+
+ About
+ -----
+
+ This library provides a robust and significantly extended implementation
+ of JSONPath for Python. It is tested with CPython 3.8 and higher.
+
+ This library differs from other JSONPath implementations in that it is a
+ full *language* implementation, meaning the JSONPath expressions are
+ first class objects, easy to analyze, transform, parse, print, and
+ extend.
+
+ Quick Start
+ -----------
+
+ To install, use pip:
+
+ .. code:: bash
+
+ $ pip install --upgrade jsonpath-ng
+
+
+ Usage
+ -----
+
+ Basic examples:
+
+ .. code:: python
+
+ $ python
+
+ >>> from jsonpath_ng import jsonpath, parse
+
+ # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
+ >>> jsonpath_expr = parse('foo[*].baz')
+
+ # Extracting values is easy
+ >>> [match.value for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
+ [1, 2]
+
+ # Matches remember where they came from
+ >>> [str(match.full_path) for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
+ ['foo.[0].baz', 'foo.[1].baz']
+
+ # Modifying values matching the path
+ >>> jsonpath_expr.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
+ {'foo': [{'baz': 3}, {'baz': 3}]}
+
+ # Modifying one of the values matching the path
+ >>> matches = jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})
+ >>> matches[0].full_path.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
+ {'foo': [{'baz': 3}, {'baz': 2}]}
+
+ # Removing all values matching a path
+ >>> jsonpath_expr.filter(lambda d: True, {'foo': [{'baz': 1}, {'baz': 2}]})
+ {'foo': [{}, {}]}
+
+ # Removing values containing particular data matching path
+ >>> jsonpath_expr.filter(lambda d: d == 2, {'foo': [{'baz': 1}, {'baz': 2}]})
+ {'foo': [{'baz': 1}, {}]}
+
+ # And this can be useful for automatically providing ids for bits of data that do not have them (currently a global switch)
+ >>> jsonpath.auto_id_field = 'id'
+ >>> [match.value for match in parse('foo[*].id').find({'foo': [{'id': 'bizzle'}, {'baz': 3}]})]
+ ['foo.bizzle', 'foo.[1]']
+
+ # A handy extension: named operators like `parent`
+ >>> [match.value for match in parse('a.*.b.`parent`.c').find({'a': {'x': {'b': 1, 'c': 'number one'}, 'y': {'b': 2, 'c': 'number two'}}})]
+ ['number two', 'number one']
+
+ # You can also build expressions directly quite easily
+ >>> from jsonpath_ng.jsonpath import Fields
+ >>> from jsonpath_ng.jsonpath import Slice
+
+ >>> jsonpath_expr_direct = Fields('foo').child(Slice('*')).child(Fields('baz')) # This is equivalent
+
+
+ Using the extended parser:
+
+ .. code:: python
+
+ $ python
+
+ >>> from jsonpath_ng.ext import parse
+
+ # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
+ >>> jsonpath_expr = parse('foo[*].baz')
+
+
+ JSONPath Syntax
+ ---------------
+
+ The JSONPath syntax supported by this library includes some additional
+ features and omits some problematic features (those that make it
+ unportable). In particular, some new operators such as ``|`` and
+ ``where`` are available, and parentheses are used for grouping not for
+ callbacks into Python, since with these changes the language is not
+ trivially associative. Also, fields may be quoted whether or not they
+ are contained in brackets.
+
+ Atomic expressions:
+
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +=======================+=============================================================================================+
+ | ``$`` | The root object |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ```this``` | The "current" object. |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ```foo``` | More generally, this syntax allows "named operators" to extend JSONPath is arbitrary ways |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | *field* | Specified field(s), described below |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ``[`` *field* ``]`` | Same as *field* |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+ | ``[`` *idx* ``]`` | Array access, described below (this is always unambiguous with field access) |
+ +-----------------------+---------------------------------------------------------------------------------------------+
+
+ Jsonpath operators:
+
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +======================================+===================================================================================+
+ | *jsonpath1* ``.`` *jsonpath2* | All nodes matched by *jsonpath2* starting at any node matching *jsonpath1* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath* ``[`` *whatever* ``]`` | Same as *jsonpath*\ ``.``\ *whatever* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``..`` *jsonpath2* | All nodes matched by *jsonpath2* that descend from any node matching *jsonpath1* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``where`` *jsonpath2* | Any nodes matching *jsonpath1* with a child matching *jsonpath2* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``wherenot`` *jsonpath2* | Any nodes matching *jsonpath1* with a child not matching *jsonpath2* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+ | *jsonpath1* ``|`` *jsonpath2* | Any nodes matching the union of *jsonpath1* and *jsonpath2* |
+ +--------------------------------------+-----------------------------------------------------------------------------------+
+
+ Field specifiers ( *field* ):
+
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +=========================+=====================================================================================+
+ | ``fieldname`` | the field ``fieldname`` (from the "current" object) |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | ``"fieldname"`` | same as above, for allowing special characters in the fieldname |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | ``'fieldname'`` | ditto |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | ``*`` | any field |
+ +-------------------------+-------------------------------------------------------------------------------------+
+ | *field* ``,`` *field* | either of the named fields (you can always build equivalent jsonpath using ``|``) |
+ +-------------------------+-------------------------------------------------------------------------------------+
+
+ Array specifiers ( *idx* ):
+
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+ | Syntax | Meaning |
+ +=========================================+=======================================================================================+
+ | ``[``\ *n*\ ``]`` | array index (may be comma-separated list) |
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+ | ``[``\ *start*\ ``?:``\ *end*\ ``?]`` | array slicing (note that *step* is unimplemented only due to lack of need thus far) |
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+ | ``[*]`` | any array index |
+ +-----------------------------------------+---------------------------------------------------------------------------------------+
+
+ Programmatic JSONPath
+ ---------------------
+
+ If you are programming in Python and would like a more robust way to
+ create JSONPath expressions that does not depend on a parser, it is very
+ easy to do so directly, and here are some examples:
+
+ - ``Root()``
+ - ``Slice(start=0, end=None, step=None)``
+ - ``Fields('foo', 'bar')``
+ - ``Index(42)``
+ - ``Child(Fields('foo'), Index(42))``
+ - ``Where(Slice(), Fields('subfield'))``
+ - ``Descendants(jsonpath, jsonpath)``
+
+
+ Extras
+ ------
+
+ - *Path data*: The result of ``JsonPath.find`` provide detailed context
+ and path data so it is easy to traverse to parent objects, print full
+ paths to pieces of data, and generate automatic ids.
+ - *Automatic Ids*: If you set ``jsonpath_ng.auto_id_field`` to a value
+ other than None, then for any piece of data missing that field, it
+ will be replaced by the JSONPath to it, giving automatic unique ids
+ to any piece of data. These ids will take into account any ids
+ already present as well.
+ - *Named operators*: Instead of using ``@`` to reference the current
+ object, this library uses ```this```. In general, any string
+ contained in backquotes can be made to be a new operator, currently
+ by extending the library.
+
+
+ Extensions
+ ----------
+
+ To use the extensions below you must import from `jsonpath_ng.ext`.
+
+ +--------------+-----------------------------------------------+
+ | name | Example |
+ +==============+===============================================+
+ | len | - ``$.objects.`len``` |
+ +--------------+-----------------------------------------------+
+ | sub | - ``$.field.`sub(/foo\\\\+(.*)/, \\\\1)``` |
+ | | - ``$.field.`sub(/regex/, replacement)``` |
+ +--------------+-----------------------------------------------+
+ | split | - ``$.field.`split(+, 2, -1)``` |
+ | | - ``$.field.`split(",", *, -1)``` |
+ | | - ``$.field.`split(' ', -1, -1)``` |
+ | | - ``$.field.`split(sep, segement, maxsplit)```|
+ +--------------+-----------------------------------------------+
+ | sorted | - ``$.objects.`sorted``` |
+ | | - ``$.objects[\\some_field]`` |
+ | | - ``$.objects[\\some_field,/other_field]`` |
+ +--------------+-----------------------------------------------+
+ | filter | - ``$.objects[?(@some_field > 5)]`` |
+ | | - ``$.objects[?some_field = "foobar"]`` |
+ | | - ``$.objects[?some_field =~ "foobar"]`` |
+ | | - ``$.objects[?some_field > 5 & other < 2]`` |
+ | | |
+ | | Supported operators: |
+ | | - Equality: ==, =, != |
+ | | - Comparison: >, >=, <, <= |
+ | | - Regex match: =~ |
+ | | |
+ | | Combine multiple criteria with '&'. |
+ | | |
+ | | Properties can only be compared to static |
+ | | values. |
+ +--------------+-----------------------------------------------+
+ | arithmetic | - ``$.foo + "_" + $.bar`` |
+ | (-+*/) | - ``$.foo * 12`` |
+ | | - ``$.objects[*].cow + $.objects[*].cat`` |
+ +--------------+-----------------------------------------------+
+
+ About arithmetic and string
+ ---------------------------
+
+ Operations are done with python operators and allows types that python
+ allows, and return [] if the operation can be done due to incompatible types.
+
+ When operators are used, a jsonpath must be be fully defined otherwise
+ jsonpath-rw-ext can't known if the expression is a string or a jsonpath field,
+ in this case it will choice string as type.
+
+ Example with data::
+
+ {
+ 'cow': 'foo',
+ 'fish': 'bar'
+ }
+
+ | ``cow + fish`` returns ``cowfish``
+ | ``$.cow + $.fish`` returns ``foobar``
+ | ``$.cow + "_" + $.fish`` returns ``foo_bar``
+ | ``$.cow + "_" + fish`` returns ``foo_fish``
+
+ About arithmetic and list
+ -------------------------
+
+ Arithmetic can be used against two lists if they have the same size.
+
+ Example with data::
+
+ {'objects': [
+ {'cow': 2, 'cat': 3},
+ {'cow': 4, 'cat': 6}
+ ]}
+
+ | ``$.objects[\*].cow + $.objects[\*].cat`` returns ``[6, 9]``
+
+ More to explore
+ ---------------
+
+ There are way too many JSONPath implementations out there to discuss.
+ Some are robust, some are toy projects that still work fine, some are
+ exercises. There will undoubtedly be many more. This one is made for use
+ in released, maintained code, and in particular for programmatic access
+ to the abstract syntax and extension. But JSONPath at its simplest just
+ isn't that complicated, so you can probably use any of them
+ successfully. Why not this one?
+
+ The original proposal, as far as I know:
+
+ - `JSONPath - XPath for
+ JSON <http://goessner.net/articles/JSONPath/>`__ by Stefan Goessner.
+
+ Other examples
+ --------------
+
+ Loading json data from file
+
+ .. code:: python
+
+ import json
+ d = json.loads('{"foo": [{"baz": 1}, {"baz": 2}]}')
+ # or
+ with open('myfile.json') as f:
+ d = json.load(f)
+
+ Special note about PLY and docstrings
+ -------------------------------------
+
+ The main parsing toolkit underlying this library,
+ `PLY <https://github.com/dabeaz/ply>`__, does not work with docstrings
+ removed. For example, ``PYTHONOPTIMIZE=2`` and ``python -OO`` will both
+ cause a failure.
+
+ Contributors
+ ------------
+
+ This package is authored and maintained by:
+
+ - `Kenn Knowles <https://github.com/kennknowles>`__
+ (`@kennknowles <https://twitter.com/KennKnowles>`__)
+ - `Tomas Aparicio <https://github.com/h2non>`
+
+ with the help of patches submitted by `these contributors <https://github.com/kennknowles/python-jsonpath-ng/graphs/contributors>`__.
+
+ Copyright and License
+ ---------------------
+
+ Copyright 2013 - Kenneth Knowles
+
+ Copyright 2017 - Tomas Aparicio
+
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
+ not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+
+ ::
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ .. _`JSONPath proposal`: http://goessner.net/articles/JsonPath/
+ .. _`jsonpath-rw`: https://github.com/kennknowles/python-jsonpath-rw
+ .. _`jsonpath-rw-ext`: https://pypi.python.org/pypi/jsonpath-rw-ext/
+
+ .. |PyPi downloads| image:: https://pypip.in/d/jsonpath-ng/badge.png
+ :target: https://pypi.python.org/pypi/jsonpath-ng
+ .. |Build Status| image:: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml/badge.svg
+ :target: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml
+ .. |PyPI| image:: https://img.shields.io/pypi/v/jsonpath-ng.svg?maxAge=2592000?style=flat-square
+ :target: https://pypi.python.org/pypi/jsonpath-ng
+
+Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
-License-File: LICENSE
-
-Python JSONPath Next-Generation |Build Status| |PyPI|
-=====================================================
-
-A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic
-and binary comparison operators, as defined in the original `JSONPath proposal`_.
-
-This packages merges both `jsonpath-rw`_ and `jsonpath-rw-ext`_ and
-provides several AST API enhancements, such as the ability to update or remove nodes in the tree.
-
-About
------
-
-This library provides a robust and significantly extended implementation
-of JSONPath for Python. It is tested with CPython 3.7 and higher.
-
-This library differs from other JSONPath implementations in that it is a
-full *language* implementation, meaning the JSONPath expressions are
-first class objects, easy to analyze, transform, parse, print, and
-extend.
-
-Quick Start
------------
-
-To install, use pip:
-
-.. code:: bash
-
- $ pip install --upgrade jsonpath-ng
-
-
-Usage
------
-
-Basic examples:
-
-.. code:: python
-
- $ python
-
- >>> from jsonpath_ng import jsonpath, parse
-
- # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
- >>> jsonpath_expr = parse('foo[*].baz')
-
- # Extracting values is easy
- >>> [match.value for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
- [1, 2]
-
- # Matches remember where they came from
- >>> [str(match.full_path) for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
- ['foo.[0].baz', 'foo.[1].baz']
-
- # Modifying values matching the path
- >>> jsonpath_expr.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
- {'foo': [{'baz': 3}, {'baz': 3}]}
-
- # Modifying one of the values matching the path
- >>> matches = jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})
- >>> matches[0].full_path.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
- {'foo': [{'baz': 3}, {'baz': 2}]}
-
- # Removing all values matching a path
- >>> jsonpath_expr.filter(lambda d: True, {'foo': [{'baz': 1}, {'baz': 2}]})
- {'foo': [{}, {}]}
-
- # Removing values containing particular data matching path
- >>> jsonpath_expr.filter(lambda d: d == 2, {'foo': [{'baz': 1}, {'baz': 2}]})
- {'foo': [{'baz': 1}, {}]}
-
- # And this can be useful for automatically providing ids for bits of data that do not have them (currently a global switch)
- >>> jsonpath.auto_id_field = 'id'
- >>> [match.value for match in parse('foo[*].id').find({'foo': [{'id': 'bizzle'}, {'baz': 3}]})]
- ['foo.bizzle', 'foo.[1]']
-
- # A handy extension: named operators like `parent`
- >>> [match.value for match in parse('a.*.b.`parent`.c').find({'a': {'x': {'b': 1, 'c': 'number one'}, 'y': {'b': 2, 'c': 'number two'}}})]
- ['number two', 'number one']
-
- # You can also build expressions directly quite easily
- >>> from jsonpath_ng.jsonpath import Fields
- >>> from jsonpath_ng.jsonpath import Slice
-
- >>> jsonpath_expr_direct = Fields('foo').child(Slice('*')).child(Fields('baz')) # This is equivalent
-
-
-Using the extended parser:
-
-.. code:: python
-
- $ python
-
- >>> from jsonpath_ng.ext import parse
-
- # A robust parser, not just a regex. (Makes powerful extensions possible; see below)
- >>> jsonpath_expr = parse('foo[*].baz')
-
-
-JSONPath Syntax
----------------
-
-The JSONPath syntax supported by this library includes some additional
-features and omits some problematic features (those that make it
-unportable). In particular, some new operators such as ``|`` and
-``where`` are available, and parentheses are used for grouping not for
-callbacks into Python, since with these changes the language is not
-trivially associative. Also, fields may be quoted whether or not they
-are contained in brackets.
-
-Atomic expressions:
-
-+-----------------------+---------------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=======================+=============================================================================================+
-| ``$`` | The root object |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ```this``` | The "current" object. |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ```foo``` | More generally, this syntax allows "named operators" to extend JSONPath is arbitrary ways |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| *field* | Specified field(s), described below |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ``[`` *field* ``]`` | Same as *field* |
-+-----------------------+---------------------------------------------------------------------------------------------+
-| ``[`` *idx* ``]`` | Array access, described below (this is always unambiguous with field access) |
-+-----------------------+---------------------------------------------------------------------------------------------+
-
-Jsonpath operators:
-
-+-------------------------------------+------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=====================================+====================================================================================+
-| *jsonpath1* ``.`` *jsonpath2* | All nodes matched by *jsonpath2* starting at any node matching *jsonpath1* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath* ``[`` *whatever* ``]`` | Same as *jsonpath*\ ``.``\ *whatever* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``..`` *jsonpath2* | All nodes matched by *jsonpath2* that descend from any node matching *jsonpath1* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``where`` *jsonpath2* | Any nodes matching *jsonpath1* with a child matching *jsonpath2* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-| *jsonpath1* ``|`` *jsonpath2* | Any nodes matching the union of *jsonpath1* and *jsonpath2* |
-+-------------------------------------+------------------------------------------------------------------------------------+
-
-Field specifiers ( *field* ):
-
-+-------------------------+-------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=========================+=====================================================================================+
-| ``fieldname`` | the field ``fieldname`` (from the "current" object) |
-+-------------------------+-------------------------------------------------------------------------------------+
-| ``"fieldname"`` | same as above, for allowing special characters in the fieldname |
-+-------------------------+-------------------------------------------------------------------------------------+
-| ``'fieldname'`` | ditto |
-+-------------------------+-------------------------------------------------------------------------------------+
-| ``*`` | any field |
-+-------------------------+-------------------------------------------------------------------------------------+
-| *field* ``,`` *field* | either of the named fields (you can always build equivalent jsonpath using ``|``) |
-+-------------------------+-------------------------------------------------------------------------------------+
-
-Array specifiers ( *idx* ):
-
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-| Syntax | Meaning |
-+=========================================+=======================================================================================+
-| ``[``\ *n*\ ``]`` | array index (may be comma-separated list) |
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-| ``[``\ *start*\ ``?:``\ *end*\ ``?]`` | array slicing (note that *step* is unimplemented only due to lack of need thus far) |
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-| ``[*]`` | any array index |
-+-----------------------------------------+---------------------------------------------------------------------------------------+
-
-Programmatic JSONPath
----------------------
-
-If you are programming in Python and would like a more robust way to
-create JSONPath expressions that does not depend on a parser, it is very
-easy to do so directly, and here are some examples:
-
-- ``Root()``
-- ``Slice(start=0, end=None, step=None)``
-- ``Fields('foo', 'bar')``
-- ``Index(42)``
-- ``Child(Fields('foo'), Index(42))``
-- ``Where(Slice(), Fields('subfield'))``
-- ``Descendants(jsonpath, jsonpath)``
-
-
-Extras
-------
-
-- *Path data*: The result of ``JsonPath.find`` provide detailed context
- and path data so it is easy to traverse to parent objects, print full
- paths to pieces of data, and generate automatic ids.
-- *Automatic Ids*: If you set ``jsonpath_ng.auto_id_field`` to a value
- other than None, then for any piece of data missing that field, it
- will be replaced by the JSONPath to it, giving automatic unique ids
- to any piece of data. These ids will take into account any ids
- already present as well.
-- *Named operators*: Instead of using ``@`` to reference the current
- object, this library uses ```this```. In general, any string
- contained in backquotes can be made to be a new operator, currently
- by extending the library.
-
-
-Extensions
-----------
-
-To use the extensions below you must import from `jsonpath_ng.ext`.
-
-+--------------+-----------------------------------------------+
-| name | Example |
-+==============+===============================================+
-| len | - ``$.objects.`len``` |
-+--------------+-----------------------------------------------+
-| sub | - ``$.field.`sub(/foo\\\\+(.*)/, \\\\1)``` |
-| | - ``$.field.`sub(/regex/, replacement)``` |
-+--------------+-----------------------------------------------+
-| split | - ``$.field.`split(+, 2, -1)``` |
-| | - ``$.field.`split(sep, segement, maxsplit)```|
-+--------------+-----------------------------------------------+
-| sorted | - ``$.objects.`sorted``` |
-| | - ``$.objects[\\some_field]`` |
-| | - ``$.objects[\\some_field,/other_field]`` |
-+--------------+-----------------------------------------------+
-| filter | - ``$.objects[?(@some_field > 5)]`` |
-| | - ``$.objects[?some_field = "foobar"]`` |
-| | - ``$.objects[?some_field =~ "foobar"]`` |
-| | - ``$.objects[?some_field > 5 & other < 2]`` |
-| | |
-| | Supported operators: |
-| | - Equality: ==, =, != |
-| | - Comparison: >, >=, <, <= |
-| | - Regex match: =~ |
-| | |
-| | Combine multiple criteria with '&'. |
-| | |
-| | Properties can only be compared to static |
-| | values. |
-+--------------+-----------------------------------------------+
-| arithmetic | - ``$.foo + "_" + $.bar`` |
-| (-+*/) | - ``$.foo * 12`` |
-| | - ``$.objects[*].cow + $.objects[*].cat`` |
-+--------------+-----------------------------------------------+
-
-About arithmetic and string
----------------------------
-
-Operations are done with python operators and allows types that python
-allows, and return [] if the operation can be done due to incompatible types.
-
-When operators are used, a jsonpath must be be fully defined otherwise
-jsonpath-rw-ext can't known if the expression is a string or a jsonpath field,
-in this case it will choice string as type.
-
-Example with data::
-
- {
- 'cow': 'foo',
- 'fish': 'bar'
- }
-
-| ``cow + fish`` returns ``cowfish``
-| ``$.cow + $.fish`` returns ``foobar``
-| ``$.cow + "_" + $.fish`` returns ``foo_bar``
-| ``$.cow + "_" + fish`` returns ``foo_fish``
-
-About arithmetic and list
--------------------------
-
-Arithmetic can be used against two lists if they have the same size.
-
-Example with data::
-
- {'objects': [
- {'cow': 2, 'cat': 3},
- {'cow': 4, 'cat': 6}
- ]}
-
-| ``$.objects[\*].cow + $.objects[\*].cat`` returns ``[6, 9]``
-
-More to explore
----------------
-
-There are way too many JSONPath implementations out there to discuss.
-Some are robust, some are toy projects that still work fine, some are
-exercises. There will undoubtedly be many more. This one is made for use
-in released, maintained code, and in particular for programmatic access
-to the abstract syntax and extension. But JSONPath at its simplest just
-isn't that complicated, so you can probably use any of them
-successfully. Why not this one?
-
-The original proposal, as far as I know:
-
-- `JSONPath - XPath for
- JSON <http://goessner.net/articles/JSONPath/>`__ by Stefan Goessner.
-
-Other examples
---------------
-
-Loading json data from file
-
-.. code:: python
-
- import json
- d = json.loads('{"foo": [{"baz": 1}, {"baz": 2}]}')
- # or
- with open('myfile.json') as f:
- d = json.load(f)
-
-Special note about PLY and docstrings
--------------------------------------
-
-The main parsing toolkit underlying this library,
-`PLY <https://github.com/dabeaz/ply>`__, does not work with docstrings
-removed. For example, ``PYTHONOPTIMIZE=2`` and ``python -OO`` will both
-cause a failure.
-
-Contributors
-------------
-
-This package is authored and maintained by:
-
-- `Kenn Knowles <https://github.com/kennknowles>`__
- (`@kennknowles <https://twitter.com/KennKnowles>`__)
-- `Tomas Aparicio <https://github.com/h2non>`
-
-with the help of patches submitted by `these contributors <https://github.com/kennknowles/python-jsonpath-ng/graphs/contributors>`__.
-
-Copyright and License
----------------------
-
-Copyright 2013 - Kenneth Knowles
-
-Copyright 2017 - Tomas Aparicio
-
-Licensed under the Apache License, Version 2.0 (the "License"); you may
-not use this file except in compliance with the License. You may obtain
-a copy of the License at
-
-::
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-.. _`JSONPath proposal`: http://goessner.net/articles/JsonPath/
-.. _`jsonpath-rw`: https://github.com/kennknowles/python-jsonpath-rw
-.. _`jsonpath-rw-ext`: https://pypi.python.org/pypi/jsonpath-rw-ext/
-
-.. |PyPi downloads| image:: https://pypip.in/d/jsonpath-ng/badge.png
- :target: https://pypi.python.org/pypi/jsonpath-ng
-.. |Build Status| image:: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml/badge.svg
- :target: https://github.com/h2non/jsonpath-ng/actions/workflows/ci.yml
-.. |PyPI| image:: https://img.shields.io/pypi/v/jsonpath-ng.svg?maxAge=2592000?style=flat-square
- :target: https://pypi.python.org/pypi/jsonpath-ng
=====================================
jsonpath_ng.egg-info/entry_points.txt
=====================================
@@ -1,2 +1,3 @@
[console_scripts]
jsonpath_ng = jsonpath_ng.bin.jsonpath:entry_point
+
=====================================
jsonpath_ng/__init__.py
=====================================
@@ -3,4 +3,4 @@ from .parser import parse # noqa
# Current package version
-__version__ = '1.6.1'
+__version__ = '1.7.0'
=====================================
jsonpath_ng/ext/iterable.py
=====================================
@@ -116,3 +116,28 @@ class Keys(JSONPath):
def __repr__(self):
return 'Keys()'
+
+class Path(JSONPath):
+ """The JSONPath referring to the path of the current object.
+ Concrete syntax is 'path`'.
+ """
+
+ def find(self, datum):
+ datum = DatumInContext.wrap(datum)
+ try:
+ value = str(datum.path)
+ except Exception as e:
+ return []
+ else:
+ return [DatumInContext(value,
+ context=datum,
+ path=Path())]
+
+ def __eq__(self, other):
+ return isinstance(other, Path)
+
+ def __str__(self):
+ return '`path`'
+
+ def __repr__(self):
+ return 'Path()'
=====================================
jsonpath_ng/ext/parser.py
=====================================
@@ -96,6 +96,8 @@ class ExtentedJsonPathParser(parser.JsonPathParser):
p[0] = _iterable.Len()
elif p[1] == 'keys':
p[0] = _iterable.Keys()
+ elif p[1] == 'path':
+ p[0] = _iterable.Path()
elif p[1] == 'sorted':
p[0] = _iterable.SortedThis()
elif p[1].startswith("split("):
=====================================
jsonpath_ng/ext/string.py
=====================================
@@ -16,7 +16,13 @@ from .. import DatumInContext, This
SUB = re.compile(r"sub\(/(.*)/,\s+(.*)\)")
-SPLIT = re.compile(r"split\((.),\s+(\d+),\s+(\d+|-1)\)")
+# Regex generated using the EZRegex package (ezregex.org)
+# EZRegex code:
+# param1 = group(optional(either("'", '"')), name='quote') + group(chunk) + earlier_group('quote')
+# param2 = group(either(optional('-') + number, '*'))
+# param3 = group(optional('-') + number)
+# pattern = 'split' + ow + '(' + ow + param1 + ow + ',' + ow + param2 + ow + ',' + ow + param3 + ow + ')'
+SPLIT = re.compile(r"split(?:\s+)?\((?:\s+)?(?P<quote>(?:(?:'|\"))?)(.+)(?P=quote)(?:\s+)?,(?:\s+)?((?:(?:\-)?\d+|\*))(?:\s+)?,(?:\s+)?((?:\-)?\d+)(?:\s+)?\)")
STR = re.compile(r"str\(\)")
@@ -60,23 +66,29 @@ class Sub(This):
class Split(This):
"""String splitter
- Concrete syntax is '`split(char, segment, max_split)`'
+ Concrete syntax is '`split(chars, segment, max_split)`'
+ `chars` can optionally be surrounded by quotes, to specify things like commas or spaces
+ `segment` can be `*` to select all
+ `max_split` can be negative, to indicate no limit
"""
def __init__(self, method=None):
m = SPLIT.match(method)
if m is None:
raise DefintionInvalid("%s is not valid" % method)
- self.char = m.group(1)
- self.segment = int(m.group(2))
- self.max_split = int(m.group(3))
+ self.chars = m.group(2)
+ self.segment = m.group(3)
+ self.max_split = int(m.group(4))
self.method = method
def find(self, datum):
datum = DatumInContext.wrap(datum)
try:
- value = datum.value.split(self.char, self.max_split)[self.segment]
- except Exception:
+ if self.segment == '*':
+ value = datum.value.split(self.chars, self.max_split)
+ else:
+ value = datum.value.split(self.chars, self.max_split)[int(self.segment)]
+ except:
return []
return [DatumInContext.wrap(value)]
=====================================
jsonpath_ng/jsonpath.py
=====================================
@@ -369,6 +369,36 @@ class Where(JSONPath):
def __hash__(self):
return hash((self.left, self.right))
+
+class WhereNot(Where):
+ """
+ Identical to ``Where``, but filters for only those nodes that
+ do *not* have a match on the right.
+
+ >>> jsonpath = WhereNot(Fields('spam'), Fields('spam'))
+ >>> jsonpath.find({"spam": {"spam": 1}})
+ []
+ >>> matches = jsonpath.find({"spam": 1})
+ >>> matches[0].value
+ 1
+
+ """
+ def find(self, data):
+ return [subdata for subdata in self.left.find(data)
+ if not self.right.find(subdata)]
+
+ def __str__(self):
+ return '%s wherenot %s' % (self.left, self.right)
+
+ def __eq__(self, other):
+ return (isinstance(other, WhereNot)
+ and other.left == self.left
+ and other.right == self.right)
+
+ def __hash__(self):
+ return hash((self.left, self.right))
+
+
class Descendants(JSONPath):
"""
JSONPath that matches first the left expression then any descendant
@@ -597,9 +627,9 @@ class Fields(JSONPath):
def _update_base(self, data, val, create):
if data is not None:
for field in self.reified_fields(DatumInContext.wrap(data)):
- if field not in data and create:
+ if create and field not in data:
data[field] = {}
- if field in data:
+ if type(data) is not bool and field in data:
if hasattr(val, '__call__'):
data[field] = val(data[field], data, field)
else:
=====================================
jsonpath_ng/lexer.py
=====================================
@@ -48,7 +48,10 @@ class JsonPathLexer:
literals = ['*', '.', '[', ']', '(', ')', '$', ',', ':', '|', '&', '~']
- reserved_words = { 'where': 'WHERE' }
+ reserved_words = {
+ 'where': 'WHERE',
+ 'wherenot': 'WHERENOT',
+ }
tokens = ['DOUBLEDOT', 'NUMBER', 'ID', 'NAMED_OPERATOR'] + list(reserved_words.values())
=====================================
jsonpath_ng/parser.py
=====================================
@@ -33,12 +33,6 @@ class JsonPathParser:
self.debug = debug
self.lexer_class = lexer_class or JsonPathLexer # Crufty but works around statefulness in PLY
- def parse(self, string, lexer = None):
- lexer = lexer or self.lexer_class()
- return self.parse_token_stream(lexer.tokenize(string))
-
- def parse_token_stream(self, token_iterator, start_symbol='jsonpath'):
-
# Since PLY has some crufty aspects and dumps files, we try to keep them local
# However, we need to derive the name of the output Python file :-/
output_directory = os.path.dirname(__file__)
@@ -47,19 +41,24 @@ class JsonPathParser:
except:
module_name = __name__
+ start_symbol = 'jsonpath'
parsing_table_module = '_'.join([module_name, start_symbol, 'parsetab'])
- # And we regenerate the parse table every time;
- # it doesn't actually take that long!
- new_parser = ply.yacc.yacc(module=self,
- debug=self.debug,
- tabmodule = parsing_table_module,
- outputdir = output_directory,
- write_tables=0,
- start = start_symbol,
- errorlog = logger)
+ # Generate the parse table
+ self.parser = ply.yacc.yacc(module=self,
+ debug=self.debug,
+ tabmodule = parsing_table_module,
+ outputdir = output_directory,
+ write_tables=0,
+ start = start_symbol,
+ errorlog = logger)
+
+ def parse(self, string, lexer = None):
+ lexer = lexer or self.lexer_class()
+ return self.parse_token_stream(lexer.tokenize(string))
- return new_parser.parse(lexer = IteratorToTokenStream(token_iterator))
+ def parse_token_stream(self, token_iterator):
+ return self.parser.parse(lexer = IteratorToTokenStream(token_iterator))
# ===================== PLY Parser specification =====================
@@ -70,6 +69,7 @@ class JsonPathParser:
('left', '|'),
('left', '&'),
('left', 'WHERE'),
+ ('left', 'WHERENOT'),
]
def p_error(self, t):
@@ -82,6 +82,7 @@ class JsonPathParser:
"""jsonpath : jsonpath '.' jsonpath
| jsonpath DOUBLEDOT jsonpath
| jsonpath WHERE jsonpath
+ | jsonpath WHERENOT jsonpath
| jsonpath '|' jsonpath
| jsonpath '&' jsonpath"""
op = p[2]
@@ -92,6 +93,8 @@ class JsonPathParser:
p[0] = Descendants(p[1], p[3])
elif op == 'where':
p[0] = Where(p[1], p[3])
+ elif op == 'wherenot':
+ p[0] = WhereNot(p[1], p[3])
elif op == '|':
p[0] = Union(p[1], p[3])
elif op == '&':
@@ -146,9 +149,12 @@ class JsonPathParser:
# Because fields in brackets cannot be '*' - that is reserved for array indices
def p_fields_or_any(self, p):
"""fields_or_any : fields
- | '*' """
+ | '*'
+ | NUMBER"""
if p[1] == '*':
p[0] = ['*']
+ elif isinstance(p[1], int):
+ p[0] = str(p[1])
else:
p[0] = p[1]
=====================================
setup.py
=====================================
@@ -4,7 +4,7 @@ import setuptools
setuptools.setup(
name='jsonpath-ng',
- version='1.6.1',
+ version='1.7.0',
description=(
'A final implementation of JSONPath for Python that aims to be '
'standard compliant, including arithmetic and binary comparison '
@@ -30,7 +30,6 @@ setuptools.setup(
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
=====================================
tests/test_jsonpath.py
=====================================
@@ -127,6 +127,16 @@ update_test_cases = (
{"foo": {"bar": 3, "flag": 1}, "baz": {"bar": 2}},
),
#
+ # WhereNot
+ # --------
+ #
+ (
+ '(* wherenot flag) .. bar',
+ {'foo': {'bar': 1, 'flag': 1}, 'baz': {'bar': 2}},
+ 4,
+ {'foo': {'bar': 1, 'flag': 1}, 'baz': {'bar': 4}},
+ ),
+ #
# Lambdas
# -------
#
@@ -136,6 +146,16 @@ update_test_cases = (
lambda x, y, z: x + 1,
{'foo': [{'baz': 2}, {'baz': 3}]}
),
+ #
+ # Update with Boolean in data
+ # ---------------------------
+ #
+ (
+ "$.*.number",
+ {'foo': ['abc', 'def'], 'bar': {'number': 123456}, 'boolean': True},
+ '98765',
+ {'foo': ['abc', 'def'], 'bar': {'number': '98765'}, 'boolean': True},
+ ),
)
@@ -256,6 +276,11 @@ find_test_cases = (
# --------
#
("A.'a.c'", {"A": {"a.c": "d"}}, ["d"], ["A.'a.c'"]),
+ #
+ # Numeric keys
+ # --------
+ #
+ ("1", {"1": "foo"}, ["foo"], ["1"]),
)
=====================================
tests/test_jsonpath_rw_ext.py
=====================================
@@ -68,6 +68,12 @@ test_cases = (
["cow", "cat"],
id="keys_dict",
),
+ pytest.param(
+ "objects.cow.`path`",
+ {"objects": {"cow": "moo", "cat": "neigh"}},
+ "cow",
+ id="path_dict",
+ ),
pytest.param(
"objects[?cow]",
{"objects": [{"cow": "moo"}, {"cat": "neigh"}]},
@@ -394,6 +400,36 @@ test_cases = (
["cat-bow"],
id="split2",
),
+ pytest.param(
+ "payload.`split(',', 2, -1)`",
+ {"payload": "foo,bar,baz"},
+ ["baz"],
+ id="split3",
+ ),
+ pytest.param(
+ 'payload.`split(", ", 2, -1)`',
+ {"payload": "foo, bar, baz"},
+ ["baz"],
+ id="split4",
+ ),
+ pytest.param(
+ 'payload.`split(", ", *, -1)`',
+ {"payload": "foo, bar, baz"},
+ [["foo", "bar", "baz"]],
+ id="split5",
+ ),
+ pytest.param(
+ 'payload.`split(", ", -1, -1)`',
+ {"payload": "foo, bar, baz"},
+ ["baz"],
+ id="split6",
+ ),
+ pytest.param(
+ "payload.`split(|, -1, 1)`",
+ {"payload": "foo|bar|baz"},
+ ["bar|baz"],
+ id="split7",
+ ),
pytest.param(
"foo[?(@.baz==1)]",
{"foo": [{"baz": 1}, {"baz": 2}]},
=====================================
tests/test_lexer.py
=====================================
@@ -24,6 +24,7 @@ token_test_cases = (
("`this`", (("this", "NAMED_OPERATOR"),)),
("|", (("|", "|"),)),
("where", (("where", "WHERE"),)),
+ ("wherenot", (("wherenot", "WHERENOT"),)),
)
=====================================
tests/test_parser.py
=====================================
@@ -1,6 +1,6 @@
import pytest
-from jsonpath_ng.jsonpath import Child, Descendants, Fields, Index, Slice, Where
+from jsonpath_ng.jsonpath import Child, Descendants, Fields, Index, Slice, Where, WhereNot
from jsonpath_ng.lexer import JsonPathLexer
from jsonpath_ng.parser import JsonPathParser
@@ -12,6 +12,7 @@ parser_test_cases = (
#
("foo", Fields("foo")),
("*", Fields("*")),
+ ("1", Fields("1")),
("baz,bizzle", Fields("baz", "bizzle")),
("[1]", Index(1)),
("[1:]", Slice(start=1)),
@@ -27,6 +28,7 @@ parser_test_cases = (
("foo.baz", Child(Fields("foo"), Fields("baz"))),
("foo.baz,bizzle", Child(Fields("foo"), Fields("baz", "bizzle"))),
("foo where baz", Where(Fields("foo"), Fields("baz"))),
+ ("foo wherenot baz", WhereNot(Fields("foo"), Fields("baz"))),
("foo..baz", Descendants(Fields("foo"), Fields("baz"))),
("foo..baz.bing", Descendants(Fields("foo"), Child(Fields("baz"), Fields("bing")))),
)
View it on GitLab: https://salsa.debian.org/debian-gis-team/jsonpath-ng/-/commit/0f47a9293856904822c205dec6f4603c43e27fe5
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/jsonpath-ng/-/commit/0f47a9293856904822c205dec6f4603c43e27fe5
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20241013/bbbc5119/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list