Metadata-Version: 2.4
Name: assignment-generator-sebastian-stigler
Version: 0.1.0
Summary: Assignment generator scaffold project
License: MIT License
        
        Copyright (c) 2026 Sebastian Stigler
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: click>=8.1
Requires-Dist: rich>=15.0.0
Description-Content-Type: text/markdown

# agen

`agen` (assignment-generator) is a Python 3.12 CLI tool that reads a source-code template file and generates two output files:

- an **assignment** file for students (placeholders replace solution blocks)
- a **solution** file for instructors (full content with solution markers)

Templates are ordinary source files (`.py`, `.c`, etc.) annotated with special comment-tagged blocks that control what appears in each output.

---

## Installation

`agen` requires Python 3.12+ and is managed with [uv](https://docs.astral.sh/uv/).

### From package index

```sh
uv tool install assignment-generator-sebastian-stigler
agen --help
```

### From source

```sh
git clone <repository-url>
cd agen
uv sync
```

This installs the package and all dependencies into a local virtual environment. The `agen` command is then available via:

```sh
uv run agen --help
```

To install the tool globally (into a dedicated isolated environment):

```sh
uv tool install .
agen --help
```

---

## Configuration

Configuration is resolved by layered merging:

1. **Built-in defaults** (always applied)
2. **Global config** — `~/.config/agen/agen-config.json` (overrides defaults)
3. **Local config** — `.agen-config.json` in the current working directory (overrides global)

`comment_tokens` entries are merged key-by-key; all other keys are replaced wholesale by the later layer.

### Generating a starter config

```sh
agen generate-config > .agen-config.json
```

### Config file format

```jsonc
{
  "comment_tokens": {
    ".py": "#",
    ".c": "//"
  },
  "assignment_marker":      "TODO",
  "solution_marker_begin":  "BEGIN SOLUTION",
  "solution_marker_end":    "END SOLUTION",
  "template_file_prefix":   "template_",
  "assignment_file_prefix": "assignment_",
  "solution_file_prefix":   "solution_",
  "assignment_only_begin":  "BEGIN ASSIGNMENT ONLY",
  "assignment_only_end":    "END ASSIGNMENT ONLY",
  "solution_only_begin":    "BEGIN SOLUTION ONLY",
  "solution_only_end":      "END SOLUTION ONLY",
  "assignment_begin":       "BEGIN ASSIGNMENT",
  "assignment_end":         "END ASSIGNMENT"
}
```

#### `comment_tokens`

A mapping of file extensions (including the leading dot) to the line-comment token for that language. `agen` uses this token when writing marker lines into the output files. Add an entry for every extension you use in templates, for example `".js": "//"` or `".sql": "--"`.

`comment_tokens` is the only key that is merged key-by-key across config layers — a later layer can add or override individual extensions without replacing the whole map.

#### Output markers (`assignment_marker`, `solution_marker_begin`, `solution_marker_end`)

These strings control the text that `agen` writes into the **output files**:

- `assignment_marker` — the placeholder comment text inserted into the assignment file wherever an `ASSIGNMENT` block appears.
- `solution_marker_begin` / `solution_marker_end` — comments wrapped around the original block content in the solution file (e.g. `# BEGIN SOLUTION` … `# END SOLUTION`).

`assignment_marker` can be a single line (for example `TODO`) or multiline text.

`assignment_marker` supports multiline text. Each non-empty line becomes a commented placeholder line using the configured comment token; empty lines stay empty.

Example config value:

```json
{
  "assignment_marker": "YOUR CODE STARTS HERE >>>\n\n<<<< YOUR CODE ENDS HERE"
}
```

Example assignment output snippet (for a Python template):

```python
def add(a, b):
    # YOUR CODE STARTS HERE >>>

    # <<<< YOUR CODE ENDS HERE
```

#### File prefixes (`template_file_prefix`, `assignment_file_prefix`, `solution_file_prefix`)

These prefixes control automatic output file naming. When `agen` derives an output path from the template filename it:

1. Strips `template_file_prefix` from the start of the template basename (if present).
2. Prepends `assignment_file_prefix` or `solution_file_prefix` to the remainder.

For example, with the defaults a template named `template_exercise.py` produces `assignment_exercise.py` and `solution_exercise.py`. You can override the output path entirely with `-a` / `-s` on the command line.

#### Template block tags (`assignment_only_begin`/`end`, `solution_only_begin`/`end`, `assignment_begin`/`end`)

These are the tag strings that `agen` looks for **inside the template file** to delimit the three special block types. Each pair marks where a block starts and ends. They must appear as the sole content of a comment line (after the comment token). Change them only if the defaults conflict with existing comments in your codebase.

### Environment variables

| Variable | Default | Description |
|---|---|---|
| `AGEN_CONFIG_BASENAME` | `agen-config.json` | Config file basename (both global and local) |
| `AGEN_GLOBAL_CONFIG_PATH` | `~/.config/agen` | Directory for the global config file |

---

## Template format

Template files are normal source files with specially tagged comment blocks. The file extension determines which line-comment token is used.

### Block types

| Block tag | Assignment output | Solution output |
|---|---|---|
| `ASSIGNMENT_ONLY` | written as-is | omitted |
| `SOLUTION_ONLY` | omitted | written as-is |
| `ASSIGNMENT` | replaced by a placeholder comment (`TODO`) | wrapped in begin/end solution markers + original content |
| *(unmarked)* | written as-is | written as-is |

### Example template (`template_exercise.py`)

```python
def add(a, b):
    # BEGIN ASSIGNMENT
    return a + b
    # END ASSIGNMENT

# BEGIN ASSIGNMENT ONLY
# Implement the add() function above.
# END ASSIGNMENT ONLY

# BEGIN SOLUTION ONLY
# Reference implementation — do not distribute.
# END SOLUTION ONLY
```

Running `agen create both template_exercise.py` produces:

**`assignment_exercise.py`**
```python
def add(a, b):
    # TODO

# Implement the add() function above.
```

**`solution_exercise.py`**
```python
def add(a, b):
    # BEGIN SOLUTION
    return a + b
    # END SOLUTION

# Reference implementation — do not distribute.
```

### File naming

By default, `agen` strips a `template_` prefix from the template basename and adds `assignment_` or `solution_` prefixes to the output files. This is configurable — see [Configuration](#configuration).

---

## Usage

```
agen [COMMAND] [OPTIONS] [ARGS]
```

### Global options

```sh
agen --version
```

Print the installed `agen` version.

### `agen check <templatefile>`

Validate and summarise a template file without writing any output.

```sh
agen check template_exercise.py
```

Prints block statistics and any warnings.

---

### `agen create assignment <templatefile>`

Generate the assignment output file only.

```sh
agen create assignment template_exercise.py
agen create assignment template_exercise.py -a custom_assignment.py   # custom output path
agen create assignment template_exercise.py -f                        # overwrite existing file
agen create assignment template_exercise.py --dry-run                 # preview without writing
agen create assignment template_exercise.py --anyway                  # skip the no-ASSIGNMENT-block guard
agen create assignment template_exercise.py -v                        # show template stats
```

---

### `agen create solution <templatefile>`

Generate the solution output file only.

```sh
agen create solution template_exercise.py
agen create solution template_exercise.py -s custom_solution.py       # custom output path
agen create solution template_exercise.py -f                          # overwrite existing file
agen create solution template_exercise.py --dry-run                   # preview without writing
agen create solution template_exercise.py -v                          # show template stats
```

---

### `agen create both <templatefile>`

Generate both assignment and solution output files in one command.

```sh
agen create both template_exercise.py
agen create both template_exercise.py -f
agen create both template_exercise.py -a out_a.py -s out_s.py
agen create both template_exercise.py --dry-run
agen create both template_exercise.py -v                              # show template stats
```

---

### `agen current-config`

Print the effective merged configuration, colour-coded by origin (default / global / local).

```sh
agen current-config
```

---

### `agen generate-config`

Print a complete default config JSON document, suitable for redirecting into a config file.

```sh
agen generate-config > .agen-config.json
```

---

## Development

```sh
uv sync                  # install dependencies
uv run pytest            # run the test suite
```
