Skip to content
Open
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
75 changes: 75 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9', '3.11', '3.12']

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

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

- name: Build engine binaries
run: python build_differ.py

- name: Run tests
run: hatch run test

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install hatch hatchling

- name: Build package
run: hatch build

- name: Check package
run: |
pip install twine
twine check dist/*
8 changes: 7 additions & 1 deletion .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ jobs:

steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -26,4 +32,4 @@ jobs:
run: hatch build
- name: Publish package
run: |
hatch publish -u "__token__" -a ${{ secrets.PYPI_API_TOKEN }}
hatch publish -u "__token__" -a ${{ secrets.PYPI_API_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ __pycache__/
# C# Build Dirs
csproj/bin/*
csproj/obj/*
docxodus/**/bin/*
docxodus/**/obj/*

# C extensions
*.so
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "docxodus"]
path = docxodus
url = https://github.com/JSv4/Docxodus.git
73 changes: 73 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# CLAUDE.md

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

## Project Overview

Python-Redlines is a Python wrapper around compiled C# binaries that generate `.docx` redline/tracked-changes documents by comparing two Word files. The Python layer handles platform detection, binary extraction, temp file management, and subprocess execution.

Two comparison engines are available:
- **XmlPowerToolsEngine** — wraps Open-XML-PowerTools WmlComparer (original engine)
- **DocxodusEngine** — wraps Docxodus, a modernized .NET 8.0 fork with better move detection

## Commands

```bash
# Run tests
hatch run test

# Run a single test
hatch run test tests/test_openxml_differ.py::test_run_redlines_with_real_files

# Run tests with coverage
hatch run cov

# Type checking
hatch run types:check

# Build C# binaries for all platforms (requires .NET 8.0 SDK)
hatch run build

# Build Python package (triggers C# build via custom hook)
hatch build

# Initialize Docxodus submodule (required before building)
git submodule update --init --recursive
```

## Architecture

The system uses a two-layer wrapper pattern with a shared base class:

1. **Python layer** (`src/python_redlines/engines.py`):
- `BaseEngine` — shared logic for binary extraction, subprocess invocation, and temp file management
- `XmlPowerToolsEngine(BaseEngine)` — sets constants for the Open-XML-PowerTools binary (`dist/`, `bin/`, `redlines`)
- `DocxodusEngine(BaseEngine)` — sets constants for the Docxodus binary (`dist_docxodus/`, `bin_docxodus/`, `redline`)

Both engines expose `run_redline(author_tag, original, modified, **kwargs)`. `DocxodusEngine` overrides `_build_command()` to translate kwargs (e.g. `detect_moves`, `detail_threshold`) into CLI flags for the Docxodus binary. `XmlPowerToolsEngine` uses the legacy 4-positional-arg format and ignores kwargs.

2. **C# binaries**:
- `csproj/Program.cs` — Open-XML-PowerTools CLI tool
- `docxodus/tools/redline/Program.cs` — Docxodus CLI tool (git submodule)

Pre-compiled binaries for 6 platform targets (linux/win/osx x x64/arm64) are stored as archives in `src/python_redlines/dist/` and `src/python_redlines/dist_docxodus/`, included in the wheel. The build script `build_differ.py` compiles both engines using `dotnet publish`.

## Key Files

- `src/python_redlines/engines.py` — BaseEngine, XmlPowerToolsEngine, and DocxodusEngine classes
- `src/python_redlines/__init__.py` — Exports all engine classes
- `src/python_redlines/__about__.py` — Single source of truth for package version
- `csproj/Program.cs` — Open-XML-PowerTools C# comparison utility
- `docxodus/` — Docxodus git submodule (tools/redline/ contains the CLI)
- `build_differ.py` — Cross-platform C# build orchestration for both engines
- `hatch_run_build_hook.py` — Hatch build hook that triggers C# compilation
- `tests/fixtures/` — Test `.docx` files (original, modified, expected_redline)

## Testing Notes

Tests must be run from the project root (fixtures use relative paths like `tests/fixtures/original.docx`). The XmlPowerToolsEngine integration test validates that comparing the fixture documents produces exactly 9 revisions. Docxodus uses a different stdout format (`"revision(s) found"` vs `"Revisions found: 9"`).

## Stdout Format Differences

- **XmlPowerToolsEngine**: `"Revisions found: 9"`
- **DocxodusEngine**: `"Redline complete: 9 revision(s) found"`
Loading
Loading