Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(mkdir:*)"
],
"deny": [],
"ask": []
}
}
148 changes: 148 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
name: Build and Release

on:
push:
branches: [ main ]
paths:
- '**/*.py'
- 'pyproject.toml'
- 'requirements*.txt'

permissions:
contents: write
id-token: write # For PyPI trusted publishing

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build pytest toml

- name: Build package
run: |
python -m build

- name: Install package
run: |
pip install dist/*.whl

- name: Test installation
run: |
python -c "import diffgetr; print('Package imported successfully')"
diffgetr --help || echo "CLI help command executed"

- name: Run unit tests
run: |
pytest tests/ -v

- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: dist
path: dist/

publish-pypi:
runs-on: ubuntu-latest
needs: build-and-test
environment: release
steps:
- uses: actions/checkout@v4

- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: dist
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true

create-github-release:
runs-on: ubuntu-latest
needs: [build-and-test, publish-pypi]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch full history for changelog

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install toml

- name: Get version and create release
run: |
python -c "
import toml
import os

# Read version from pyproject.toml
with open('pyproject.toml', 'r') as f:
data = toml.load(f)

version = data['project']['version']
description = data['project']['description']

# Set environment variables for next step
with open(os.environ['GITHUB_ENV'], 'a') as f:
f.write(f'VERSION={version}\n')
f.write(f'DESCRIPTION={description}\n')
"

- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: dist
path: dist/

- name: Generate changelog
run: |
echo "## Changes" > CHANGELOG.md
echo "" >> CHANGELOG.md

# Get commits since last tag
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$LAST_TAG" ]; then
echo "Changes since $LAST_TAG:" >> CHANGELOG.md
git log $LAST_TAG..HEAD --pretty=format:"- %s (%h)" >> CHANGELOG.md
else
echo "Initial release" >> CHANGELOG.md
git log --pretty=format:"- %s (%h)" >> CHANGELOG.md
fi

echo "" >> CHANGELOG.md
echo "## Package Files" >> CHANGELOG.md
echo "" >> CHANGELOG.md
echo "The following files are available for download:" >> CHANGELOG.md
for file in dist/*; do
echo "- $(basename $file)" >> CHANGELOG.md
done

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.VERSION }}
name: Release v${{ env.VERSION }}
body_path: CHANGELOG.md
files: dist/*
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
132 changes: 132 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: Pull Request Checks

on:
pull_request:
branches: [ main ]
paths:
- '**/*.py'
- 'pyproject.toml'
- 'requirements*.txt'
- '.github/workflows/**'

permissions:
contents: write
pull-requests: write

jobs:
version-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install toml requests

- name: Check if version exists as GitHub release
run: |
python -c "
import toml
import requests
import sys

# Read current version from pyproject.toml
with open('pyproject.toml', 'r') as f:
data = toml.load(f)

current_version = data['project']['version']
print(f'Current version: {current_version}')

# Check if this version exists as a GitHub release
repo = '${{ github.repository }}'
url = f'https://api.github.com/repos/{repo}/releases/tags/v{current_version}'

response = requests.get(url)
if response.status_code == 200:
print(f'ERROR: Release v{current_version} already exists!')
print('Please update the version in pyproject.toml before merging.')
sys.exit(1)
else:
print(f'Version v{current_version} is available for release.')
"

build-and-test:
runs-on: ubuntu-latest
needs: version-check
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build pytest black

- name: Build package
run: |
python -m build

- name: Install package
run: |
pip install dist/*.whl

- name: Test installation
run: |
python -c "import diffgetr; print('Package imported successfully')"
diffgetr --help || echo "CLI help command executed"

- name: Run unit tests
run: |
pytest tests/ -v || echo "No tests found yet"

format-code:
runs-on: ubuntu-latest
needs: build-and-test
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref }}

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install black
run: |
python -m pip install --upgrade pip
pip install black

- name: Format code with black
run: |
black --check --diff diffgetr/ || echo "Formatting needed"
black diffgetr/

- name: Check for changes
id: verify-changed-files
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
else
echo "changed=false" >> $GITHUB_OUTPUT
fi

- name: Commit formatted code
if: steps.verify-changed-files.outputs.changed == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add -A
git commit -m "🤖 Auto-format code with black"
git push
89 changes: 89 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

**diffgetr** is a Python library for comparing nested data structures with detailed diff reporting and interactive navigation. It provides advanced diff capabilities beyond basic comparison, featuring pattern recognition, multiple output formats, and dictionary-like navigation through diff results.

## Installation and Development Commands

```bash
# Install the package locally
pip install .

# Install in development mode
pip install -e .

# Test the command line tool
diffgetr file1.json file2.json path.to.key
```

## Core Architecture

### Main Class: `diff_get`

The library centers around a single class `diff_get` located in `diffgetr/diff_get.py:9`. This class:

1. **Wraps DeepDiff**: Uses the `deepdiff` library as the underlying comparison engine with configurable parameters (`diffgetr/diff_get.py:22-24`)

2. **Enables Navigation**: Implements `__getitem__` to allow dictionary-like traversal through nested diff results (`diffgetr/diff_get.py:35-41`)

3. **Type Coercion**: Automatically converts lists/tuples to dictionaries for consistent comparison (`diffgetr/diff_get.py:14-17`)

4. **Location Tracking**: Maintains path context through the `loc` property for debugging and display (`diffgetr/diff_get.py:26-33`)

### Key Features

#### Interactive Navigation (`diffgetr/diff_get.py:35-57`)
- Dictionary-style access: `diff['key1']['nested_key']`
- IPython tab completion support via `_ipython_key_completions_`
- Error handling with context-aware KeyError messages

#### Multiple Output Formats
- **Summary**: Pattern recognition with frequency counts (`diff_summary()` at `diffgetr/diff_get.py:239-292`)
- **Detailed**: Full diff with pretty printing (`diff_all()` at `diffgetr/diff_get.py:96-109`)
- **Side-by-side**: Tabular comparison with percentage changes (`diff_sidebyside()` at `diffgetr/diff_get.py:111-237`)

#### Pattern Recognition (`diffgetr/diff_get.py:260-264`)
- UUID detection and abstraction
- CSV-like number sequence recognition
- Path normalization for cleaner summaries

### Command Line Interface

Entry point defined in `pyproject.toml:29` as `diffgetr = "diffgetr.diff_get:main"`

The CLI (`main()` function at `diffgetr/diff_get.py:295-329`) supports:
- JSON file comparison
- Dot-notation path navigation
- Array index navigation with bracket notation

### Configuration Options

#### DeepDiff Parameters (`diffgetr/diff_get.py:21-24`)
Default settings:
- `ignore_numeric_type_changes=True`
- `significant_digits=3`

Can be overridden via `deep_diff_kw` parameter.

#### Behavior Modifiers
- `ignore_added=False`: Filter out added items to focus on changes/removals
- Configurable precision for numeric comparisons
- Threshold-based filtering in side-by-side output

## Development Notes

### Code Structure
- Single module design with one main class
- Heavy use of property decorators for computed values
- String/bytes handling for flexible output streams
- Recursive instantiation for navigation

### Key Dependencies
- `deepdiff>=6.0.0`: Core comparison engine
- Standard library: `json`, `re`, `argparse`, `pprint`

### Testing Approach
The library includes comprehensive examples in the README showing various use cases. When adding features, ensure compatibility with existing navigation patterns and output formats.
Loading