Function-level diff tool for Python files between Git refs
Project description
Function Diff
A Python package for analyzing function-level changes in Python code between Git branches or commits. Perfect for code reviews, CI/CD pipelines, and understanding code evolution.
Features
- Function-level Analysis: Detects added, removed, and modified functions and methods
- Git Integration: Works with any Git repository (local or remote)
- HTML Reports: Generates beautiful HTML tables for email notifications
- Email Support: Send reports via Gmail or Azure SMTP
- CI/CD Ready: Easy integration with GitHub Actions and other CI systems
- CLI Tool: Simple command-line interface
- Python API: Use as a library in your own Python scripts
Installation
pip install function-diff
Usage
Command Line
Basic Usage
# Compare two branches in current repo
function-diff main feature-branch
# Compare and include added functions
function-diff main HEAD --include-added
# Use a specific repository path
function-diff main feature --repo-path /path/to/repo
# Clone and compare remote repository
function-diff main feature --repo-url https://github.com/user/repo.git
With Email Notifications
# Send report via email
export EMAIL_USER="your-email@gmail.com"
export EMAIL_PASS="your-app-password"
export EMAIL_TO="recipient@example.com"
export SMTP_HOST="smtp.gmail.com"
export SMTP_PORT="587"
function-diff main feature-branch --send-email
Version Information
function-diff --version
Python API
from function_diff import analyze, print_report, build_html_report
# Analyze function-level changes
report = analyze(
repo_url="https://github.com/user/repo.git",
base_branch="main",
target_branch="feature",
repo_path=None # or provide local path
)
# Print to console
print_report(report, include_added=True)
# Get HTML report
html = build_html_report(report, include_added=False)
print(html)
Send Email from Python
from function_diff import analyze
from function_diff.emailer import send_function_diff_email
import os
# Set environment variables
os.environ["EMAIL_USER"] = "your-email@gmail.com"
os.environ["EMAIL_PASS"] = "your-app-password"
os.environ["EMAIL_TO"] = "recipient@example.com"
os.environ["SMTP_HOST"] = "smtp.gmail.com"
os.environ["SMTP_PORT"] = "587"
# Analyze and send email
report = analyze(None, "main", "feature", repo_path="/path/to/repo")
send_function_diff_email(report, "main", "feature", include_added=False)
GitHub Actions Integration
Basic Function Diff on Pull Request
name: Function Diff Report
on:
pull_request:
types: [opened]
jobs:
function-diff:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install function-diff
run: pip install function-diff
- name: Run function comparison
run: |
function-diff \
${{ github.event.pull_request.base.ref }} \
${{ github.event.pull_request.head.ref }} \
--repo-path ${{ github.workspace }}
With Email Notification
name: Function Diff with Email
on:
pull_request:
types: [opened]
workflow_dispatch:
inputs:
base_branch:
description: 'Base branch'
required: true
default: 'main'
target_branch:
description: 'Target branch'
required: true
send_email:
description: 'Send email report'
type: boolean
default: false
jobs:
function-diff:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install function-diff
run: pip install function-diff
- name: Run function comparison with email
env:
EMAIL_USER: ${{ secrets.EMAIL_USER }}
EMAIL_PASS: ${{ secrets.EMAIL_PASS }}
EMAIL_FROM: ${{ secrets.EMAIL_FROM }}
EMAIL_TO: ${{ secrets.EMAIL_TO }}
EMAIL_CC: ${{ secrets.EMAIL_CC }}
SMTP_HOST: ${{ secrets.SMTP_HOST }}
SMTP_PORT: ${{ secrets.SMTP_PORT }}
GITHUB_REPOSITORY: ${{ github.repository }}
BASE_REF: ${{ github.event.pull_request.base.ref || github.event.inputs.base_branch }}
TARGET_REF: ${{ github.event.pull_request.head.ref || github.event.inputs.target_branch }}
run: |
function-diff \
"$BASE_REF" \
"$TARGET_REF" \
--repo-path ${{ github.workspace }} \
${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.send_email == 'true') && '--send-email' || '' }}
Configuration
Environment Variables
Required for Email
EMAIL_USER- SMTP username for authenticationEMAIL_PASS- SMTP password or app-specific passwordEMAIL_TO- Comma-separated recipient emails
Optional for Email
EMAIL_FROM- Sender email address (default:EMAIL_USER)EMAIL_CC- Comma-separated CC email addressesSMTP_HOST- SMTP server hostname (default:smtp.gmail.com)SMTP_PORT- SMTP server port (default:587)
Optional Context Variables
GITHUB_REPOSITORY- Repository name for email reportsGITHUB_ACTOR- GitHub usernameBASE_REF- Override base branch from CLITARGET_REF- Override target branch from CLIGH_PAT- GitHub Personal Access Token for private repositories
SMTP Configuration
Gmail
export EMAIL_USER="your-email@gmail.com"
export EMAIL_PASS="your-app-password" # Generate at https://myaccount.google.com/apppasswords
export EMAIL_TO="recipient@example.com"
export SMTP_HOST="smtp.gmail.com"
export SMTP_PORT="587"
Azure/Office 365
export EMAIL_USER="your-username@company.com"
export EMAIL_FROM="noreply@company.com" # Can be different from USER
export EMAIL_PASS="your-password"
export EMAIL_TO="recipient@example.com"
export SMTP_HOST="smtp.office365.com"
export SMTP_PORT="587"
Custom SMTP Server
export EMAIL_USER="username"
export EMAIL_PASS="password"
export EMAIL_TO="recipient@example.com"
export SMTP_HOST="smtp.yourserver.com"
export SMTP_PORT="587"
How It Works
The tool analyzes Python files that changed between two Git references and:
- Extracts Functions: Parses Python AST to find all functions and class methods
- Compares: Identifies functions that were added, removed, or modified
- Reports: Generates human-readable or HTML reports
- Notifies: Optionally sends email notifications with styled HTML tables
What Counts as Modified?
A function is considered modified if:
- The function body changed
- Decorators were added, removed, or changed
- Function signature changed (parameters, return type)
Examples
Example Output (Console)
File: src/utils/helpers.py
Removed: old_function
Modified: process_data, validate_input
File: src/core/engine.py
Modified: calculate_metrics
Example Output (HTML)
The HTML report includes a styled table with:
- Repository information
- Base and target branches
- Implementor name (if using Jira integration)
- Detailed function changes per file
Private Repositories
For private repositories, set the GH_PAT environment variable:
export GH_PAT="ghp_your_github_personal_access_token"
git config --global url."https://${GH_PAT}@github.com/".insteadOf "https://github.com/"
Or use SSH authentication with your SSH keys.
Requirements
- Python 3.8 or higher
- Git installed and available in PATH
- SMTP access for email notifications (optional)
Advanced Usage
Integrating with Jira
If you have zephyr-jira-linker installed, the tool will automatically extract implementor information from branch names containing Jira issue keys (e.g., PROJ-1234).
Custom Report Processing
from function_diff import analyze, extract_functions
# Analyze changes
report = analyze(None, "main", "feature", repo_path=".")
# Process each file
for file_path, changes in report.items():
print(f"File: {file_path}")
print(f" Added: {len(changes['added'])} functions")
print(f" Removed: {len(changes['removed'])} functions")
print(f" Modified: {len(changes['modified'])} functions")
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see LICENSE file for details
Author
Pandiyaraj Karuppasamy
- Email: pandiyarajk@live.com
- GitHub: @Pandiyarajk
- PyPI: pandiyarajk
Links
Changelog
See CHANGELOG.md for version history and changes.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file function_diff-0.1.0.tar.gz.
File metadata
- Download URL: function_diff-0.1.0.tar.gz
- Upload date:
- Size: 32.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63c136080b78977700483b8540474c58ca91f02bbbe4eb8ad826610097d9b631
|
|
| MD5 |
f85907bf3d72384742b9a7cc199ae4e1
|
|
| BLAKE2b-256 |
65d40f9e91dc6cc802298eafda59d68dd8bcc3a06d8597adafbe44585ea0783b
|
File details
Details for the file function_diff-0.1.0-py3-none-any.whl.
File metadata
- Download URL: function_diff-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8e1dd492749e120e4786c314ced8402ab7a1ee50adf675e5c0568e4aa46eac7
|
|
| MD5 |
64c446deba30d0c26035205f05c2bb60
|
|
| BLAKE2b-256 |
3d35be617377415f75aa68574216895e8bbe75a27b87a17a304e98eb4dfdcdac
|