Skip to main content

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 authentication
  • EMAIL_PASS - SMTP password or app-specific password
  • EMAIL_TO - Comma-separated recipient emails

Optional for Email

  • EMAIL_FROM - Sender email address (default: EMAIL_USER)
  • EMAIL_CC - Comma-separated CC email addresses
  • SMTP_HOST - SMTP server hostname (default: smtp.gmail.com)
  • SMTP_PORT - SMTP server port (default: 587)

Optional Context Variables

  • GITHUB_REPOSITORY - Repository name for email reports
  • GITHUB_ACTOR - GitHub username
  • BASE_REF - Override base branch from CLI
  • TARGET_REF - Override target branch from CLI
  • GH_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:

  1. Extracts Functions: Parses Python AST to find all functions and class methods
  2. Compares: Identifies functions that were added, removed, or modified
  3. Reports: Generates human-readable or HTML reports
  4. 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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE file for details

Author

Pandiyaraj Karuppasamy

Links

Changelog

See CHANGELOG.md for version history and changes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

function_diff-0.1.0.tar.gz (32.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

function_diff-0.1.0-py3-none-any.whl (15.2 kB view details)

Uploaded Python 3

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

Hashes for function_diff-0.1.0.tar.gz
Algorithm Hash digest
SHA256 63c136080b78977700483b8540474c58ca91f02bbbe4eb8ad826610097d9b631
MD5 f85907bf3d72384742b9a7cc199ae4e1
BLAKE2b-256 65d40f9e91dc6cc802298eafda59d68dd8bcc3a06d8597adafbe44585ea0783b

See more details on using hashes here.

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

Hashes for function_diff-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d8e1dd492749e120e4786c314ced8402ab7a1ee50adf675e5c0568e4aa46eac7
MD5 64c446deba30d0c26035205f05c2bb60
BLAKE2b-256 3d35be617377415f75aa68574216895e8bbe75a27b87a17a304e98eb4dfdcdac

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page