Metadata-Version: 2.3
Name: xdiffly
Version: 0.3.1
Summary: X-Diff: a general-purpose tool for exploring differences between datasets (netCDF today, more targets to come)
Author: Antonio Mariani
Author-email: Antonio Mariani <antonio.mariani@cmcc.it>
Requires-Dist: xarray>=2024.6.0,<2025.0.0
Requires-Dist: pandas>=2.2.2,<3.0.0
Requires-Dist: netcdf4>=1.7.1,<2.0.0
Requires-Dist: rich>=13.7.1,<14.0.0
Requires-Dist: click>=8.3.1,<9.0.0
Requires-Dist: dask>=2024.6.0,<2025.0.0
Requires-Dist: distributed>=2024.6.0,<2025.0.0
Requires-Dist: bokeh>=3.1.0,<4.0.0
Requires-Python: >=3.10, <3.14
Project-URL: Changelog, https://github.com/anto6715/X-Diff/blob/master/CHANGES.md
Project-URL: Homepage, https://github.com/anto6715/X-Diff
Project-URL: Issues, https://github.com/anto6715/X-Diff/issues
Project-URL: Repository, https://github.com/anto6715/X-Diff
Description-Content-Type: text/markdown

# X-Diff

`xdiff` is the CLI for **X-Diff**, a general diff tool name where `X` can stand for different comparison targets.
Today, X-Diff supports detailed comparison of netCDF files and helps users identify differences between datasets stored
in netCDF format.

![Python](https://img.shields.io/badge/Python-3.10--3.13-blue.svg)
[![Tests](https://github.com/anto6715/X-Diff/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/anto6715/X-Diff/actions/workflows/tests.yml)
[![Coverage](https://codecov.io/gh/anto6715/X-Diff/graph/badge.svg?branch=master)](https://codecov.io/gh/anto6715/X-Diff)

![Output](https://github.com/anto6715/X-Diff/raw/master/docs/output.png)

## Installation

### Install uv

Follow the official installer:

```shell
curl -LsSf https://astral.sh/uv/install.sh | sh
```

### Install in a local virtual environment (recommended for development)

`xdiff` currently supports Python 3.10 through 3.13. Create the project-local environment and install dependencies from `uv.lock` with:

```shell
uv sync --python 3.13
```

Run the CLI through uv:

```shell
uv run xdiff --help
```

### Install globally with uv tool

The package is published on PyPI as `xdiffly`; it installs the `xdiff` command.

```shell
uv tool install --python 3.13 xdiffly
```

`uv tool install` installs `xdiffly` in uv's global tool environment (similar to `pipx`), not inside this repository's `.venv`. After installation, run it as `xdiff`.

## Usage

From a source checkout, prefix commands with `uv run`. If you installed with `uv tool install`, use `xdiff` directly.

```shell
uv run xdiff [OPTIONS] COMMAND [ARGS]...

  Explore differences between datasets.

Options:
  --version   Show the version and exit.
  -h, --help  Show this message and exit.

Commands:
  dirs   Compare two directories of datasets.
  files  Compare two dataset files directly, even if their filenames differ.

```

### Select Variables

It is possible to choose which parameter to compare:

```shell
uv run xdiff dirs folder1 folder2 -v votemper -v vosaline
```

![Variables](https://github.com/anto6715/X-Diff/raw/master/docs/variables.png)

### Filter files

By default **xdiff** iterates over all files in **folder1** and expects to find them in **folder2**. Using filters,
it is possible to select only a subset of input files. For example:

```shell
uv run xdiff dirs folder1 folder2 -f "*_grid_T.nc"
```

### Compare files with different filenames

It is possible to compare two files with different filenames directly:

```shell
uv run xdiff files a/my-simu_19820101_grid_T.nc b/another-exp_19820101_grid_T.nc
```

For directory comparisons, files with different names can still be matched if they share a common substring.
For example, given:

- `a/my-simu_19820101_grid_T.nc`
- `b/another-exp_19820101_grid_T.nc`

Pass the common part as a regex pattern:

```shell
uv run xdiff dirs folder1 folder2 --common-pattern "\d{8}"
```

The pattern is matched against both filenames using `re.findall`. Two files are considered a pair when the
pattern produces the same match in both names — in this case the shared date `19820101`.

### Dask file-level execution

`xdiff` still defaults to serial execution, but Dask support is installed by default. When you want Dask-backed file-level execution, see [docs/dask.md](docs/dask.md) for local-cluster and external-scheduler examples.

## Testing

GitHub Actions runs the test suite on every pull request and on pushes to `master`. Coverage is uploaded from CI to Codecov, which powers the README coverage badge.

To run the same checks locally, install the project and dev dependencies with a single command:

```shell
uv sync --group dev
```

Then run the suite:

```shell
uv run pytest --cov --cov-report=term-missing --cov-report=xml
```

The Codecov badge will start showing a real percentage after the workflow runs successfully on GitHub and the repository is connected to Codecov.

## Changelog

This repository uses `towncrier` for release notes. Every pull request must include a changelog entry under `changes.d/` for user-facing changes, for example:

```text
changes.d/123.bugfix.md
changes.d/124.doc.md
changes.d/+internal-cleanup.misc.md
```

Use the pull request number as the filename prefix when you want Towncrier to render a linked PR reference. With the current configuration, `changes.d/123.bugfix.md` will render as `[#123]` in `CHANGES.md`. Use `+` instead of a number when there is no associated PR to link.

Create a changelog entry with the Towncrier CLI:

```shell
uv run towncrier create 123.bugfix.md --content "Improved CLI filtering so directory comparisons skip unrelated files more reliably."
```

Create an orphan entry when there is no associated PR:

```shell
uv run towncrier create +internal-cleanup.misc.md --content "Cleaned up internal comparison helpers and simplified related tests."
```

If you omit `--content`, `towncrier create` will open your editor so you can write the entry interactively.

Validate or preview changelog entries locally with:

```shell
uv run towncrier build --draft --version 0.2.6
```

To mirror the CI-style branch check after committing or staging your changelog entry:

```shell
git fetch origin master:refs/remotes/origin/master
uv run towncrier check --compare-with origin/master --staged
```

Release notes are generated from `release/X.Y.Z` branches. Open a PR from `release/X.Y.Z` to `master`, and CI will:

1. set `pyproject.toml` to version `X.Y.Z`
2. run `towncrier build --yes --version X.Y.Z`
3. commit the updated `CHANGES.md` and consumed changelog entries back to the release branch

In normal feature work, contributors should create entries with `towncrier create` and optionally preview them with `towncrier build --draft`. The final non-draft `towncrier build --yes` step is handled by the release workflow in [`.github/workflows/release-changelog.yml`](.github/workflows/release-changelog.yml).

After the release PR is merged, merge `master` back into `develop` so the generated changelog and consumed entry deletions return to the integration branch.

## Author

- Antonio Mariani (antonio.mariani@cmcc.it)

## Contributing

Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.

## Contact

For any questions or suggestions, please open an issue on the project's GitHub repository.
