Skip to content

jakesower/json-expressions-python

Repository files navigation

JSON Expressions - Python Port

A powerful Python expression engine for JSON-based dynamic computations and function composition, ported from the original JavaScript version.

Overview

JSON Expressions provides a declarative syntax for creating complex logic, transformations, and calculations that can be serialized, stored, and executed safely. Perfect for configuration-driven applications, business rules engines, and anywhere you need dynamic logic represented as data.

Installation

# From the py directory
pip install -e .

# Or install pytest for running tests
pip install pytest pytest-cov

Quick Start

# If installed as package:
# from json_expressions import default_expression_engine

# If running from source:
from . import default_expression_engine
# or 
import sys; sys.path.append('path/to/py/'); from py import default_expression_engine

# Simple comparison
result = default_expression_engine.apply({"$gt": 18}, 25)
print(result)  # True

# Get nested value with default
result = default_expression_engine.apply(
    {"$get": {"path": "user.email", "default": "no-email@example.com"}}, 
    {"user": {"name": "Amara"}}
)
print(result)  # "no-email@example.com"

# Array operations
data = [{"name": "Zahra", "age": 4}, {"name": "Kenji", "age": 5}]
result = default_expression_engine.apply(
    {"$map": {"$get": "name"}}, 
    data
)
print(result)  # ["Zahra", "Kenji"]

# Static evaluation (no input data needed)
result = default_expression_engine.evaluate({"$sum": [1, 2, 3, 4, 5]})
print(result)  # 15

Available Expressions

Core Expressions

  • $get - Retrieve values from objects with optional defaults
  • $prop - Get object properties (strict mode)
  • $pipe - Chain expressions left-to-right
  • $compose - Chain expressions right-to-left (mathematical order)
  • $literal - Return literal values
  • $debug - Log and return values
  • $ensurePath - Validate paths exist
  • $isDefined - Check if value is defined

Comparison Expressions

  • $eq, $ne - Equality/inequality with deep comparison
  • $gt, $gte, $lt, $lte - Numerical comparisons
  • $in, $nin - Array membership tests
  • $matchesRegex - Regular expression matching with flags
  • $matchesLike - SQL LIKE pattern matching
  • $matchesGlob - Unix shell GLOB pattern matching

Logical Expressions

  • $and, $or, $not - Boolean logic operations

Math Expressions

  • $add, $subtract, $multiply, $divide, $modulo - Arithmetic operations

Conditional Expressions

  • $if - If/then/else logic
  • $switch - Switch statement with deep equality matching
  • $case - Case statement with boolean predicate matching

Array/Iterative Expressions

  • $map, $filter, $find - Array transformations
  • $all, $any - Array predicates
  • $append, $prepend - Array concatenation
  • $join - Join arrays to strings
  • $reverse - Reverse arrays
  • $flatMap - Map and flatten

Aggregative Expressions

  • $count, $sum - Basic aggregations
  • $min, $max - Min/max values
  • $mean, $median, $mode - Statistical operations

Generative Expressions

  • $random - Generate random numbers with precision control
  • $uuid - Generate UUID v4 strings

Temporal Expressions

  • $nowUTC, $nowLocal - Current time as ISO strings
  • $timestamp - Current time as milliseconds

Running Tests

# Run all tests
python run_tests.py

# Run with coverage
python run_tests.py --coverage

# Run specific test file
python -m pytest test/definitions/test_core.py -v

# Run specific test class
python -m pytest test/definitions/test_core.py::TestGet -v

Architecture

The Python port maintains the same architecture as the JavaScript original:

  • ExpressionEngine: Core evaluation engine
  • Definitions: Modular expression implementations
  • Type Safety: Full type hints throughout
  • Error Handling: Descriptive error messages with suggestions

Custom Expressions

You can create custom expressions and combine them with built-ins:

# If installed as package:
# from json_expressions import create_expression_engine, default_expressions

# If running from source:
from . import create_expression_engine, default_expressions

def title_case_apply(operand, input_data, context):
    return input_data.title()

def title_case_evaluate(operand, context):
    return context["evaluate"](operand).title()

custom_engine = create_expression_engine({
    **default_expressions,
    "$titleCase": {
        "apply": title_case_apply,
        "evaluate": title_case_evaluate,
    }
})

result = custom_engine.apply({"$titleCase": None}, "hello world")
print(result)  # "Hello World"

Differences from JavaScript Version

  • Type Hints: Full type annotations for better IDE support
  • Error Handling: Python-style exceptions (ValueError, TypeError)
  • None vs Undefined: Uses Python's None instead of JavaScript's undefined
  • Deep Equality: Custom implementation for object/list comparison
  • Regex Flags: Maps JavaScript regex flags to Python equivalents
  • Temporal Operations: Uses Python's datetime and timezone handling

Contributing

  1. Clone the repository
  2. Install dependencies: pip install pytest pytest-cov
  3. Run tests: python run_tests.py
  4. Make your changes
  5. Ensure tests pass and add new tests for new features
  6. Submit a pull request

License

MIT License

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages