Metadata-Version: 2.4
Name: gantt2drawio
Version: 0.7.0
Summary: Generate editable draw.io Gantt charts from simple YAML files.
Author: gantt2drawio contributors
License: MIT
Keywords: gantt,drawio,diagrams.net,yaml,project-management
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Scheduling
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=6.2; extra == "dev"
Requires-Dist: flake8>=3.8; extra == "dev"
Dynamic: license-file

# gantt2drawio

`gantt2drawio` turns a small YAML project definition into an editable [draw.io](https://www.drawio.com/) (`.drawio`) Gantt chart.

The package is intentionally a renderer, not a full project-management system. You provide calendar dates or relative positions such as `M0` and `M6`; the package handles validation, timeline layout, and draw.io XML generation.

## See it in action

<table>
  <tr>
    <th>1. YAML input</th>
    <th>2. Terminal preview</th>
  </tr>
  <tr>
    <td align="center" valign="top" width="36%">
      <img src="img/config.png" alt="YAML configuration for a relative-month Gantt chart" width="350">
    </td>
    <td align="center" valign="top" width="64%">
      <img src="img/preview.png" alt="Terminal preview produced by gantt2drawio" width="937">
    </td>
  </tr>
</table>

<p align="center"><strong>3. Editable draw.io output</strong></p>

<p align="center">
  <img src="img/relative.png" alt="Editable relative-month Gantt chart generated by gantt2drawio" width="1011">
</p>

## What it supports

- Calendar tasks using ISO dates and calendar-day (`d`) or week (`w`) durations
- Relative-month tasks using positions such as `M0` and durations such as `6M`
- Milestones on calendar dates or within complete relative months
- Optional compact rows with milestone IDs placed on their preceding task bars
- Optional inherited starts for relative tasks
- Weekly, monthly, or automatically selected timelines
- Optional task and milestone colors
- Configurable wrapping, clipping, and ellipsis for long item names
- Strict validation with field-specific errors
- Editable draw.io shapes with stable IDs
- A command-line interface and a small Python API
- Dependency-free Unicode and ASCII terminal previews
- Deterministic, uncompressed XML suitable for version control

Version 0.7 deliberately does not include dependencies, automatic scheduling, nested groups, progress bars, business-day calendars, or critical-path analysis.

## Installation

The package requires Python 3.9 or newer.

Install the package from PyPI:

```bash
python -m pip install gantt2drawio
```

Install the project from this directory:

```bash
python -m pip install .
```

For development, install it in editable mode with the test dependency:

```bash
python -m pip install -e ".[dev]"
```

## Quick start

### Calendar timeline

Create `project.yaml`:

```yaml
version: 1

chart:
  title: Research project
  scale: month

items:
  - id: literature-review
    type: task
    name: Literature review
    start: 2026-08-01
    duration: 4w

  - id: experiments
    type: task
    name: Run experiments
    start: 2026-09-01
    end: 2026-11-30
    color: "#59A14F"

  - id: final-report
    type: milestone
    name: Final report submitted
    date: 2026-12-15
```

Validate it:

```bash
gantt2drawio validate project.yaml
```

Generate the diagram:

```bash
gantt2drawio build project.yaml -o project.drawio
```

If `-o` is omitted, the output uses the input name with a `.drawio` suffix:

```bash
gantt2drawio build project.yaml
# writes project.drawio
```

Open the resulting file in the draw.io desktop application or import it into diagrams.net. Task bars, milestone diamonds, labels, and table cells are native editable diagram elements.

### Relative timeline

Use relative mode when exact calendar dates are not known:

```yaml
version: 1

chart:
  title: Relative research programme
  mode: relative
  unit: month
  start: M0
  end: M18

items:
  - id: literature-review
    type: task
    name: Literature review
    duration: 6M

  - id: first-review
    type: milestone
    name: First review
    date: M3

  - id: experiments
    type: task
    name: Run experiments
    start: M4
    end: M12
```

Because the first task has no `start`, it inherits `chart.start`. Its `6M`
duration covers the six complete months `M0` through `M5`. Save the definition
as `relative-project.yaml` and generate it in exactly the same way:

```bash
gantt2drawio build relative-project.yaml
```

## Terminal preview

Preview a chart without creating a draw.io file:

```bash
gantt2drawio preview examples/relative.yaml
```

Example output:

```text
Relative research programme — M0 to M18 (relative-month)

Item                M0   M1   M2   M3   M4   M5
────────────────────────────────────────────────
Literature review  ███████████████████████████
First review                    ◆
Run experiments                      ██████████

█ task  ◆ milestone
```

The preview uses the same resolved dates, relative positions, and timeline
geometry as the draw.io renderer. It scales to the current terminal width and
truncates long names when necessary.

Useful preview options:

```bash
# Select a width
gantt2drawio preview project.yaml --width 120

# Use portable ASCII characters
gantt2drawio preview project.yaml --ascii
```

`build` prints a preview automatically when its output is an interactive terminal. This avoids adding noise when the command is redirected or used in a script. The behavior can be controlled explicitly:

```bash
# Force a preview when output is redirected
gantt2drawio build project.yaml --preview

# Suppress an interactive preview
gantt2drawio build project.yaml --no-preview

# Configure the build preview
gantt2drawio build project.yaml --preview-width 120 --ascii-preview
```

## YAML reference

### Top level

| Field | Required | Description |
| --- | --- | --- |
| `version` | No | Schema version. If present, it must be the integer `1`. |
| `chart` | No | Chart-wide configuration. |
| `items` | Yes | A non-empty list of tasks and milestones. |

Unknown fields are rejected. This helps catch spelling mistakes rather than silently ignoring them.

### Chart

Calendar mode is the default:

```yaml
chart:
  title: Research project
  scale: auto
  start: 2026-01-01
  end: 2026-12-31
```

| Field | Default | Description |
| --- | --- | --- |
| `title` | `Gantt chart` | Title shown above the chart. |
| `mode` | `calendar` | `calendar` or `relative`. |
| `compact` | `false` | Place milestones on the preceding task row and show only task/milestone IDs. |
| `scale` | `auto` | Calendar mode only: `week`, `month`, or `auto`. |
| `unit` | `month` | Relative mode only. Version 0.6 supports `month`. |
| `start` | Mode-dependent | An ISO date or relative position such as `M0`. |
| `end` | Latest item | An inclusive ISO date or relative month such as `M18`. |
| `label_width` | `240` | Item-name column width, from `120` to `600`. |
| `label_max_lines` | `2` | Maximum displayed lines for `ellipsis` or `clip`, from `1` to `10`. |
| `label_overflow` | `ellipsis` | `ellipsis`, `wrap`, or `clip`. |

`auto` selects a weekly timeline for projects up to 120 days and a monthly
timeline for longer projects. Explicit chart bounds may extend the item range,
but may not exclude an item.

Relative mode uses equal-width abstract month intervals:

```yaml
chart:
  mode: relative
  unit: month
  start: M0
  end: M18
```

`chart.start` defaults to `M0` in relative mode. `chart.end` is optional and is derived from the latest task or milestone. Calendar dates and relative positions cannot be mixed in the same chart. `scale` is not used in relative mode because `unit` determines the timeline.

### Tasks

Every task requires `id`, `type`, and `name`, plus exactly one of `end` or
`duration`.

In calendar mode, `start` is required:

Using an explicit end date:

```yaml
- id: experiments
  type: task
  name: Run experiments
  start: 2026-09-01
  end: 2026-11-30
```

Using a duration:

```yaml
- id: review
  type: task
  name: Literature review
  start: 2026-08-01
  duration: 10d
```

End dates are inclusive. Therefore, a task starting on `2026-08-01` with `duration: 10d` ends on `2026-08-10`.

Supported duration units are:

| Suffix | Meaning | Example |
| --- | --- | --- |
| `d` | Calendar days | `10d` |
| `w` | Seven-day weeks | `4w` |

In relative mode, `start` may be omitted. An omitted start inherits `chart.start`, which defaults to `M0`:

```yaml
- id: work-package
  type: task
  name: Work package
  duration: 6M
```

This task starts on the first day of `M0` and ends on the last day of `M5`,
representing exactly six complete relative months. An explicit range uses
inclusive month semantics:

```yaml
- id: experiments
  type: task
  name: Run experiments
  start: M4
  end: M12
```

Relative positions must be non-negative integer values such as `M0`, `M3`, or `M18`. Relative durations use an uppercase `M`, such as `1M` or `6M`.

Timeline columns represent complete months and are labelled `M0`, `M1`, `M2`,
and so on. Both `start` and `end` are inclusive: a task with `start: M0` and
`end: M6` spans seven full columns, `M0` through `M6`. A task with `start: M0`
and `duration: 6M` spans `M0` through `M5`.

### Milestones

A milestone requires `id`, `type`, `name`, and `date`:

```yaml
- id: approval
  type: milestone
  name: Protocol approved
  date: 2026-09-18
```

In relative mode, `date` identifies a complete relative month:

```yaml
- id: approval
  type: milestone
  name: Protocol approved
  date: M3
```

The milestone diamond is placed in the centre of the `M3` month cell.

### Compact mode

Set `chart.compact` to `true` to remove separate milestone rows:

```yaml
chart:
  mode: relative
  compact: true
  end: M8

items:
  - id: T1
    type: task
    name: Literature review
    duration: 6M

  - id: M1
    type: milestone
    name: Initial review
    date: M2

  - id: M2
    type: milestone
    name: Review complete
    date: M5
```

Compact mode displays `T1` in the task column and places diamonds labelled
`M1` and `M2` on the same row at their timeline positions. Each milestone is
attached to the nearest preceding task and remains attached until another task
entry begins. Its date must fall within that task's inclusive start/end range,
so the diamond can be drawn on the colored duration bar. Multiple milestones
may share one task row. A milestone before the first task is rejected because
it has no task to attach to.

Task and milestone names are hidden visually in compact mode, but their
complete values remain available as `fullName` and `tooltip` metadata in the
draw.io XML. The terminal preview follows the same grouping and ID-only display.
The regular one-item-per-row layout remains the default.

### Long item names

Control task and milestone name layout through the chart settings:

```yaml
chart:
  label_width: 240
  label_max_lines: 2
  label_overflow: ellipsis
```

The available overflow modes are:

| Mode | Behavior |
| --- | --- |
| `ellipsis` | Show at most `label_max_lines` and add `...` when text is omitted. |
| `wrap` | Show the complete name and expand the row height as necessary. |
| `clip` | Show at most `label_max_lines` without adding `...`. |

Wrapping prefers word boundaries, breaks unusually long words when necessary, and treats Chinese, Japanese, and Korean characters as double-width. Task bars and milestone diamonds remain vertically centered when a row expands.

The complete original name is always retained in the generated XML as `fullName` and `tooltip` metadata, even when the visible label is shortened.

### IDs and colors

IDs must be unique and may contain letters, numbers, dots, underscores, and hyphens. They are used to create stable draw.io cell IDs.

Colors are optional six-digit hexadecimal values:

```yaml
color: "#4C78A8"
```

Tasks default to blue and milestones default to red.

## Python API

Generate a file directly:

```python
from gantt2drawio import render_file

render_file("project.yaml", "project.drawio")
```

Or validate and render in memory:

```python
from gantt2drawio import load_project, render

project = load_project("project.yaml")
xml = render(project)
```

Terminal previews are also available through the Python API:

```python
from gantt2drawio import load_project, render_preview

project = load_project("project.yaml")
print(render_preview(project, width=100))
```

Validation failures raise `GanttValidationError`; file access failures raise `GanttInputError`. Both inherit from `GanttError`.

## Validation errors

The validator reports the YAML location and all issues it can safely identify:

```text
project.yaml is not a valid Gantt definition:
  - items[0].duration must use a positive 'd' or 'w' duration such as '10d' or '4w'
  - items[1].date must be a valid ISO date in YYYY-MM-DD form
```

The CLI returns status code `0` on success and `2` for validation or file
errors.

## Examples

- `examples/basic.yaml` demonstrates a monthly research plan.
- `examples/weekly.yaml` demonstrates a short weekly plan.
- `examples/relative.yaml` demonstrates an 18-month relative plan.
- `examples/compact.yaml` demonstrates multiple milestones on each task row.
- `examples/long-labels.yaml` demonstrates ellipsis with English and Chinese names.

Generate all examples with:

```bash
gantt2drawio build examples/basic.yaml
gantt2drawio build examples/weekly.yaml
gantt2drawio build examples/relative.yaml
gantt2drawio build examples/compact.yaml
gantt2drawio build examples/long-labels.yaml
```

## Development

Run the test suite:

```bash
python -m pytest
```

Run the static style and import checks:

```bash
python -m flake8 src tests
```

The tests cover calendar and relative durations, strict YAML validation,
inclusive calendar dates, inclusive relative-month semantics, timeline geometry,
Unicode-aware label formatting, terminal previews, deterministic XML
rendering, and all CLI commands.

## License

MIT
