JSON Matching Expressions library that allows declarative extraction of elements from JSON documents using a query language
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
JMESPath (pronounced "james path") allows you to declaratively specify how to extract elements from a JSON document using a query language designed specifically for JSON. It provides a simple yet powerful syntax for navigating complex JSON structures, supporting operations like accessing nested objects, filtering arrays, projecting data from collections, and applying built-in functions for data transformation.
pip install jmespathimport jmespathFor accessing specific components:
from jmespath import search, compile, Options
from jmespath.exceptions import (
JMESPathError, ParseError, JMESPathTypeError,
IncompleteExpressionError, LexerError, ArityError,
VariadictArityError, EmptyExpressionError, UnknownFunctionError
)
from jmespath import functions # For custom functionsimport jmespath
# Simple path extraction
data = {'foo': {'bar': 'baz'}}
result = jmespath.search('foo.bar', data)
# Returns: 'baz'
# Array operations
data = {'users': [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}]}
names = jmespath.search('users[*].name', data)
# Returns: ['Alice', 'Bob']
# Filtering with conditions
adults = jmespath.search('users[?age >= `30`]', data)
# Returns: [{'name': 'Alice', 'age': 30}]
# Compiled expressions for reuse
expression = jmespath.compile('users[*].name')
names1 = expression.search(data1)
names2 = expression.search(data2)JMESPath uses a multi-stage processing pipeline:
The architecture enables caching of parsed expressions for performance and provides comprehensive error reporting with precise location information.
Primary interface for searching JSON data with JMESPath expressions, supporting both one-time queries and compiled expressions for repeated use.
def search(expression, data, options=None):
"""
Search data using JMESPath expression.
Args:
expression (str): JMESPath expression string
data: Python data structure to search (dict, list, etc.)
options (Options, optional): Options for controlling evaluation
Returns:
any: Extracted data matching the expression
"""
def compile(expression):
"""
Compile JMESPath expression into reusable parsed expression.
Args:
expression (str): JMESPath expression string
Returns:
ParsedResult: Object with search(data, options=None) method
"""Control how JMESPath expressions are evaluated, including dictionary class selection and custom function registration.
class Options:
"""Options to control how a JMESPath expression is evaluated."""
def __init__(self, dict_cls=None, custom_functions=None):
"""
Initialize evaluation options.
Args:
dict_cls: Class to use when creating dictionaries (default: dict)
custom_functions: Custom function registry instance
"""Comprehensive error handling for different types of JMESPath failures, from syntax errors to type mismatches.
class JMESPathError(ValueError):
"""Base exception for all JMESPath errors."""
class ParseError(JMESPathError):
"""Invalid JMESPath expression parse error."""
def __init__(self, lex_position, token_value, token_type, msg="Invalid jmespath expression"):
"""
Args:
lex_position (int): Position in expression where error occurred
token_value (str): Token value that caused error
token_type (str): Type of token that caused error
msg (str): Error message
"""
class IncompleteExpressionError(ParseError):
"""Incomplete JMESPath expression error."""
class LexerError(ParseError):
"""Lexical analysis error."""
class EmptyExpressionError(JMESPathError):
"""Empty JMESPath expression error."""
class ArityError(ParseError):
"""Wrong number of arguments to function."""
def __init__(self, expected, actual, name):
"""
Args:
expected (int): Expected number of arguments
actual (int): Actual number of arguments provided
name (str): Function name
"""
class VariadictArityError(ArityError):
"""Too few arguments for variadic function."""
class JMESPathTypeError(JMESPathError):
"""Type error in function argument."""
def __init__(self, function_name, current_value, actual_type, expected_types):
"""
Args:
function_name (str): Name of function
current_value: The problematic value
actual_type (str): Actual type found
expected_types (list): Expected types
"""
class UnknownFunctionError(JMESPathError):
"""Unknown function name error."""JMESPath provides a comprehensive set of built-in functions organized by functionality. All functions are used within JMESPath expressions, not called directly from Python.
# Mathematical operations for numeric data
abs(number) # Absolute value
avg(array_number) # Average of numeric array
ceil(number) # Ceiling of number
floor(number) # Floor of number
max(array_number) # Maximum value in numeric array
min(array_number) # Minimum value in numeric array
sum(array_number) # Sum of numeric array# Array manipulation and analysis
length(array|object|string) # Length of array, object, or string
reverse(array) # Reverse array order
sort(array) # Sort array
sort_by(array, expression) # Sort array by expression result
max_by(array, expression) # Find maximum element by expression
min_by(array, expression) # Find minimum element by expression
map(expression, array) # Apply expression to each array element# Object manipulation operations
keys(object) # Get object keys as array
values(object) # Get object values as array
merge(object...) # Merge multiple objects (variadic)# String operations and testing
contains(array|string, any) # Check if array/string contains value
ends_with(string, string) # Check if string ends with suffix
starts_with(string, string) # Check if string starts with prefix
join(string, array_string) # Join string array with separator# Type checking and conversion
type(any) # Get type of value ("string", "number", "array", "object", "boolean", "null")
not_null(any...) # Return first non-null value (variadic)
to_array(any) # Convert value to array
to_string(any) # Convert value to string
to_number(string) # Convert string to number# Mathematical functions
jmespath.search('avg(scores)', {'scores': [85, 92, 78, 96]})
# Returns: 87.75
# Array functions
jmespath.search('sort_by(users, &age)', {
'users': [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}]
})
# Returns: [{'name': 'Bob', 'age': 25}, {'name': 'Alice', 'age': 30}]
# String functions
jmespath.search('join(`, `, names)', {'names': ['Alice', 'Bob', 'Charlie']})
# Returns: "Alice, Bob, Charlie"
# Type functions
jmespath.search('not_null(missing, backup, default)', {
'missing': None, 'backup': None, 'default': 'fallback'
})
# Returns: "fallback"import jmespath
from collections import OrderedDict
# Using custom dictionary class for ordered output
options = jmespath.Options(dict_cls=OrderedDict)
result = jmespath.search('{name: name, age: age}', user_data, options)
# Compiled expressions with options
expression = jmespath.compile('{name: name, age: age}')
result = expression.search(user_data, options)import jmespath
from jmespath.exceptions import ParseError, JMESPathTypeError
try:
result = jmespath.search('invalid..syntax', data)
except ParseError as e:
print(f"Syntax error at position {e.lex_position}: {e}")
except JMESPathTypeError as e:
print(f"Type error in {e.function_name}: {e}")
except jmespath.JMESPathError as e:
print(f"JMESPath error: {e}")JMESPath supports custom functions through subclassing. Create custom functions by extending the base Functions class.
import jmespath
from jmespath import functions
# Create a subclass of functions.Functions
class CustomFunctions(functions.Functions):
# Create methods starting with "_func_" and decorate with @signature
@functions.signature({'types': ['string']})
def _func_unique_letters(self, s):
# Given a string s, return sorted unique letters: 'ccbbadd' -> 'abcd'
return ''.join(sorted(set(s)))
@functions.signature({'types': ['number']}, {'types': ['number']})
def _func_my_add(self, x, y):
return x + y
# Use custom functions with Options
options = jmespath.Options(custom_functions=CustomFunctions())
# Apply custom functions in expressions
result = jmespath.search('my_add(`1`, `2`)', {}, options)
# Returns: 3
result = jmespath.search('foo.bar | unique_letters(@)',
{'foo': {'bar': 'ccbbadd'}}, options)
# Returns: "abcd"@functions.signature(*signature_dicts)
def _func_function_name(self, *args):
"""
Custom function implementation.
Args:
signature_dicts: Type specifications for each parameter
Format: {'types': ['string', 'number', 'array', 'object', 'boolean', 'null']}
Special: {'types': [], 'variadic': True} for variadic functions
args: Function arguments matching signature types
Returns:
any: Function result
"""__version__: str # Library version string, currently "1.0.1"
class ParsedResult:
"""Compiled JMESPath expression returned by compile()."""
expression: str # Original expression string
parsed: dict # Parsed AST (internal use)
def search(self, data, options=None):
"""
Search data using the compiled expression.
Args:
data: Python data structure to search
options (Options, optional): Options for controlling evaluation
Returns:
any: Extracted data matching the expression
"""JMESPath expressions use a JSON-specific query language with the following key syntax:
foo.bar - Access nested objectsfoo[0] - Access array elements by indexfoo[1:3] - Slice arraysfoo[*].bar - Project over arrays{name: name, id: id} - Create new objectsfoo[?bar > 10] - Filter arrays with conditionslength(foo) - Apply built-in functionsfoo | bar - Chain operations@ - Reference current node in expressionsSee JMESPath Tutorial for comprehensive language documentation.
JMESPath includes a command-line tool for interactive JSON querying.
# Search JSON from stdin
echo '{"foo": {"bar": "baz"}}' | jp.py 'foo.bar'
# Search JSON from file
jp.py 'users[*].name' -f data.json
# Display AST for debugging
jp.py 'foo.bar' --ast# jp.py command line arguments:
# expression (required): JMESPath expression to evaluate
# -f, --filename: Input JSON file (default: stdin)
# --ast: Pretty print AST instead of searching