CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-jsondiff

Diff JSON and JSON-like structures in Python with multiple syntax support and bidirectional patching

Pending
Overview
Eval results
Files

cli.mddocs/

Command Line Interface

File-based diff operations with support for multiple input formats and syntax options. The jdiff command provides a convenient way to compare JSON and YAML files from the command line with all the power of the jsondiff library.

Capabilities

Command Usage

The jdiff command is installed automatically with the jsondiff package and provides file-based diff operations.

jdiff [-h] [-p] [-s {compact,symmetric,explicit,rightonly}] [-i INDENT] [-f {json,yaml}] first second

# Positional arguments:
#   first                 Path to first file to compare
#   second                Path to second file to compare (or diff file when using --patch)

# Optional arguments:
#   -h, --help           Show help message and exit
#   -p, --patch          Apply patch mode: treat second file as diff to apply to first
#   -s, --syntax         Diff syntax for output formatting (default: compact)
#   -i, --indent         Number of spaces for indentation, None for compact (default: None)
#   -f, --format         File format for input and output (default: json)

Basic Diff Operations

Compare two files and output the difference using various syntax options.

Usage Examples:

# Basic JSON file comparison
jdiff config1.json config2.json

# With pretty-printed output
jdiff config1.json config2.json -i 2

# Using explicit syntax for readability
jdiff data1.json data2.json -s explicit -i 2

# Compact output (default)
jdiff file1.json file2.json -s compact

# YAML file comparison
jdiff config1.yaml config2.yaml -f yaml

# Mixed format with YAML output formatting
jdiff data1.json data2.json -f yaml -i 2

Sample Input and Output:

# config1.json
{
  "database": {
    "host": "localhost",
    "port": 5432,
    "name": "myapp"
  },
  "debug": false
}

# config2.json  
{
  "database": {
    "host": "production.db.com",
    "port": 5432,
    "name": "myapp_prod"
  },
  "debug": true,
  "cache": {
    "enabled": true
  }
}

# Command: jdiff config1.json config2.json -s explicit -i 2
# Output:
{
  "$insert": {
    "cache": {
      "enabled": true
    }
  },
  "$update": {
    "database": {
      "host": "production.db.com",
      "name": "myapp_prod"
    },
    "debug": true
  }
}

Patch Operations

Apply a previously computed diff to a file to produce the modified version.

Usage Examples:

# Create a diff and save it
jdiff original.json modified.json > changes.json

# Apply the diff to the original file
jdiff original.json changes.json --patch

# Apply patch with pretty formatting
jdiff original.json changes.json --patch -i 2

# YAML patch operations
jdiff config.yaml patch.yaml --patch -f yaml

# Chain operations: create diff, then apply it
jdiff file1.json file2.json > diff.json
jdiff file1.json diff.json --patch > result.json

Patch Workflow Example:

# Step 1: Create original file (original.json)
{
  "version": "1.0",
  "features": ["auth", "logging"]
}

# Step 2: Create target file (target.json)  
{
  "version": "1.1", 
  "features": ["auth", "logging", "caching"],
  "experimental": true
}

# Step 3: Generate diff
jdiff original.json target.json -i 2 > upgrade.json

# upgrade.json contains:
{
  "version": "1.1",
  "features": {
    "$insert": [
      [2, "caching"]
    ]
  },
  "experimental": true
}

# Step 4: Apply diff to original
jdiff original.json upgrade.json --patch -i 2

# Output matches target.json:
{
  "version": "1.1",
  "features": [
    "auth", 
    "logging",
    "caching"
  ],
  "experimental": true
}

Format Support

Handle both JSON and YAML files with automatic format detection and conversion.

Usage Examples:

# JSON to JSON (default)
jdiff data1.json data2.json

# YAML to YAML
jdiff config1.yaml config2.yaml -f yaml

# JSON input with YAML-formatted output
jdiff data1.json data2.json -f yaml -i 2

# YAML input with JSON-formatted output  
jdiff config1.yaml config2.yaml -f json -i 2

Format Conversion Example:

# config1.yaml
database:
  host: localhost
  port: 5432
debug: false

# config2.yaml
database:
  host: remote-db
  port: 5432
debug: true
cache:
  ttl: 300

# Command: jdiff config1.yaml config2.yaml -f json -s explicit -i 2
# Output (JSON format):
{
  "$insert": {
    "cache": {
      "ttl": 300
    }
  },
  "$update": {
    "database": {
      "host": "remote-db"
    },
    "debug": true
  }
}

# Command: jdiff config1.yaml config2.yaml -f yaml -s explicit
# Output (YAML format):
$insert:
  cache:
    ttl: 300
$update:
  database:
    host: remote-db
  debug: true

Syntax Options

Choose from different diff representation formats based on your needs.

Usage Examples:

# Compact syntax (minimal output, default)
jdiff file1.json file2.json -s compact

# Explicit syntax (clear operation labels)
jdiff file1.json file2.json -s explicit

# Symmetric syntax (bidirectional, includes original values)
jdiff file1.json file2.json -s symmetric

# Right-only syntax (focus on final values)
jdiff file1.json file2.json -s rightonly

Syntax Comparison Example:

# Input files:
# file1.json: {"a": 1, "b": 2, "c": 3}
# file2.json: {"a": 1, "b": 5, "d": 4}

# Compact syntax:
jdiff file1.json file2.json -s compact
# Output: {"b": 5, "d": 4, "$delete": ["c"]}

# Explicit syntax:
jdiff file1.json file2.json -s explicit  
# Output: {"$insert": {"d": 4}, "$update": {"b": 5}, "$delete": ["c"]}

# Symmetric syntax:
jdiff file1.json file2.json -s symmetric
# Output: {"b": [2, 5], "$insert": {"d": 4}, "$delete": {"c": 3}}

# Right-only syntax:
jdiff file1.json file2.json -s rightonly
# Output: {"b": 5, "d": 4, "$delete": ["c"]}

CLI Implementation

The command-line interface is implemented in the jsondiff.cli module and provides structured argument parsing and error handling.

def main():
    """Command-line interface entry point."""
    
def load_file(serializer, file_path):
    """
    Load and parse file using specified serializer.
    
    Parameters:
    - serializer: Serializer instance for the file format
    - file_path: str, path to file to load
    
    Returns:
    dict or None: Parsed data or None if error occurred (error messages printed to stdout)
    """

Error Handling

The CLI provides clear error messages for common issues:

# File not found
$ jdiff nonexistent.json file2.json
nonexistent.json does not exist

# Invalid JSON/YAML
$ jdiff invalid.json file2.json  
invalid.json is not valid json

# Invalid format specification
$ jdiff file1.json file2.json -f xml
jdiff: error: argument -f/--format: invalid choice: 'xml' (choose from 'json', 'yaml')

# Invalid syntax specification
$ jdiff file1.json file2.json -s invalid
jdiff: error: argument -s/--syntax: invalid choice: 'invalid' (choose from 'compact', 'symmetric', 'explicit', 'rightonly')

# Help information
$ jdiff --help
usage: jdiff [-h] [-p] [-s {compact,symmetric,explicit,rightonly}] [-i INDENT] [-f {json,yaml}] first second
...

Integration with Shell Scripts

The CLI tool integrates well with shell scripts and automation workflows:

#!/bin/bash

# Configuration diff checker
check_config_changes() {
    local original="$1"
    local modified="$2"
    
    # Check if files exist
    if [[ ! -f "$original" ]] || [[ ! -f "$modified" ]]; then
        echo "Error: Files not found"
        return 1
    fi
    
    # Generate diff
    local diff_output=$(jdiff "$original" "$modified" -s explicit 2>/dev/null)
    
    # Check if there are changes
    if [[ "$diff_output" == "{}" ]]; then
        echo "No configuration changes detected"
        return 0
    else
        echo "Configuration changes detected:"
        echo "$diff_output" | jq '.' 2>/dev/null || echo "$diff_output"
        return 1
    fi
}

# Usage
check_config_changes "prod-config.json" "staging-config.json"

# Automated deployment diff
generate_deployment_diff() {
    local current_config="$1" 
    local target_config="$2"
    local diff_file="deployment-changes.json"
    
    jdiff "$current_config" "$target_config" -s compact > "$diff_file"
    
    if [[ -s "$diff_file" ]]; then
        echo "Deployment changes saved to $diff_file"
        # Apply changes
        jdiff "$current_config" "$diff_file" --patch > "updated-config.json"
        echo "Updated configuration saved to updated-config.json"
    else
        echo "No deployment changes needed"
        rm "$diff_file"
    fi
}

Performance Considerations

The CLI tool is optimized for file-based operations:

  • Memory usage: Files are loaded entirely into memory; consider file sizes for large datasets
  • Format detection: File format is determined by the -f parameter, not file extension
  • Output buffering: Large diffs are written directly to stdout without buffering
  • Error handling: Parsing errors are caught and reported clearly without stack traces

Install with Tessl CLI

npx tessl i tessl/pypi-jsondiff

docs

cli.md

core-operations.md

diff-syntaxes.md

index.md

jsondiff-class.md

serialization.md

tile.json