Skip to content

Commit b878e97

Browse files
committed
Merge branch 'runtime' into develop
* runtime: Add support for custom functions Rename decorator to signature Allow custom functions to be provided via Options Move interpreter to exprefs Update tox to run 3.5 Syntax highlight python examples Update changelog with 0.9.0 features Raise LexerError on invalid numbers
2 parents 9c2b819 + 6ccaed4 commit b878e97

File tree

10 files changed

+241
-91
lines changed

10 files changed

+241
-91
lines changed

CHANGELOG.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
0.9.0
2+
=====
3+
4+
* Add support for new lines with tokens in an expression
5+
* Add support for `JEP 9 <http://jmespath.org/proposals/improved-filters.html>`__,
6+
which introduces "and" expressions, "unary" expressions, "not" expressions,
7+
and "paren" expressions
8+
* Fix issue with hardcoded path in ``jp.py`` executable
9+
(`issue 90 <https://github.com/jmespath/jmespath.py/issues/90>`__,
10+
`issue 88 <https://github.com/jmespath/jmespath.py/issues/88>`__,
11+
`issue 82 <https://github.com/jmespath/jmespath.py/issues/82>`__)
12+
13+
114
0.8.0
215
=====
316

README.rst

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,19 @@ API
4848

4949
The ``jmespath.py`` library has two functions
5050
that operate on python data structures. You can use ``search``
51-
and give it the jmespath expression and the data::
51+
and give it the jmespath expression and the data:
52+
53+
.. code:: python
5254
5355
>>> import jmespath
5456
>>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}})
5557
'baz'
5658
5759
Similar to the ``re`` module, you can use the ``compile`` function
5860
to compile the JMESPath expression and use this parsed expression
59-
to perform repeated searches::
61+
to perform repeated searches:
62+
63+
.. code:: python
6064
6165
>>> import jmespath
6266
>>> expression = jmespath.compile('foo.bar')
@@ -75,7 +79,9 @@ Options
7579
You can provide an instance of ``jmespath.Options`` to control how
7680
a JMESPath expression is evaluated. The most common scenario for
7781
using an ``Options`` instance is if you want to have ordered output
78-
of your dict keys. To do this you can use either of these options::
82+
of your dict keys. To do this you can use either of these options:
83+
84+
.. code:: python
7985
8086
>>> import jmespath
8187
>>> jmespath.search('{a: a, b: b},
@@ -90,6 +96,85 @@ of your dict keys. To do this you can use either of these options::
9096
... jmespath.Options(dict_cls=collections.OrderedDict))
9197
9298
99+
Custom Functions
100+
~~~~~~~~~~~~~~~~
101+
102+
The JMESPath language has numerous
103+
`built-in functions
104+
<http://jmespath.org/specification.html#built-in-functions>`__, but it is
105+
also possible to add your own custom functions. Keep in mind that
106+
custom function support in jmespath.py is experimental and the API may
107+
change based on feedback.
108+
109+
**If you have a custom function that you've found useful, consider submitting
110+
it to jmespath.site and propose that it be added to the JMESPath language.**
111+
You can submit proposals
112+
`here <https://github.com/jmespath/jmespath.site/issues>`__.
113+
114+
To create custom functions:
115+
116+
* Create a subclass of ``jmespath.functions.Functions``.
117+
* Create a method with the name ``_func_<your function name>``.
118+
* Apply the ``jmespath.functions.signature`` decorator that indicates
119+
the expected types of the function arguments.
120+
* Provide an instance of your subclass in a ``jmespath.Options`` object.
121+
122+
Below are a few examples:
123+
124+
.. code:: python
125+
126+
import jmespath
127+
from jmespath import functions
128+
129+
# 1. Create a subclass of functions.Functions.
130+
# The function.Functions base class has logic
131+
# that introspects all of its methods and automatically
132+
# registers your custom functions in its function table.
133+
class CustomFunctions(functions.Functions):
134+
135+
# 2 and 3. Create a function that starts with _func_
136+
# and decorate it with @signature which indicates its
137+
# expected types.
138+
# In this example, we're creating a jmespath function
139+
# called "unique_letters" that accepts a single argument
140+
# with an expected type "string".
141+
@functions.signature({'types': ['string']})
142+
def _func_unique_letters(self, s):
143+
# Given a string s, return a sorted
144+
# string of unique letters: 'ccbbadd' -> 'abcd'
145+
return ''.join(sorted(set(s)))
146+
147+
# Here's another example. This is creating
148+
# a jmespath function called "my_add" that expects
149+
# two arguments, both of which should be of type number.
150+
@functions.signature({'types': ['number']}, {'types': ['number']})
151+
def _func_my_add(self, x, y):
152+
return x + y
153+
154+
# 4. Provide an instance of your subclass in a Options object.
155+
options = jmespath.Options(custom_functions=CustomFunctions())
156+
157+
# Provide this value to jmespath.search:
158+
# This will print 3
159+
print(
160+
jmespath.search(
161+
'my_add(`1`, `2`)', {}, options=options)
162+
)
163+
164+
# This will print "abcd"
165+
print(
166+
jmespath.search(
167+
'foo.bar | unique_letters(@)',
168+
{'foo': {'bar': 'ccbbadd'}},
169+
options=options)
170+
)
171+
172+
Again, if you come up with useful functions that you think make
173+
sense in the JMESPath language (and make sense to implement in all
174+
JMESPath libraries, not just python), please let us know at
175+
`jmespath.site <https://github.com/jmespath/jmespath.site/issues>`__.
176+
177+
93178
Specification
94179
=============
95180

jmespath/compat.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33

44
PY2 = sys.version_info[0] == 2
55

6+
7+
def with_metaclass(meta, *bases):
8+
# Taken from flask/six.
9+
class metaclass(meta):
10+
def __new__(cls, name, this_bases, d):
11+
return meta(name, bases, d)
12+
return type.__new__(metaclass, 'temporary_class', (), {})
13+
14+
615
if PY2:
716
text_type = unicode
817
string_type = basestring

0 commit comments

Comments
 (0)