Metadata-Version: 2.1
Name: aoctools
Version: 0.1.0
Summary: A CLI for working with Advent of Code (AOC) problems
Home-page: https://github.com/klittlepage/aoctools
Author: Kelly Littlepage
Author-email: kelly@klittlepage.com
License: UNKNOWN
Download-URL: https://github.com/klittlepage/aoctools/archive/0.1.0.tar.gz
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: requests (<3,>=2.25.0)
Requires-Dist: python-dotenv (>=0.15.0)
Provides-Extra: dev
Requires-Dist: pylint ; extra == 'dev'
Requires-Dist: mypy ; extra == 'dev'
Requires-Dist: autopep8 ; extra == 'dev'
Requires-Dist: pre-commit ; extra == 'dev'
Requires-Dist: wheel ; extra == 'dev'

# Automating your Advent of Code (AOC) Workflow: aoctools

## Introduction

`aoctools` is a command line interface (cli) that helps you automate
[Advent of Code (AOC)](https://adventofcode.com/) boilerplate, e.g., downloading
the day's problem input and writing python boilerplate.

## Workflow

### Step 0: Install

`pip3 install aoctools`

### Step 1: Initialize a project

```text
usage: aoctools init [-h] root_path year

positional arguments:
  root_path   the root project directory
  year
```

The `init` command will create an `aoctools` project at the path that you
specify.

### Step 2: Bootstrap the boilerplate for a new day

Make sure that you set an environment variable named `AOC_SESSION_COOKIE` to the
`session` cookie of your AOC login; in Chrome, you can obtain this cookie by
opening Developer Tools (`View > Developer > Developer Tools`), opening the
`Application` tab, and looking for the value that appears next to `session`.

As an alternative to setting this variable every time that you run the tool, `aoctools` supports `.env` files. You can create a `.env` file under your
project directory and run `aoctools` from said directory for an even more
ergonomic workflow. NB: `.env` files are loaded relative to the working
directory (where you run `aoctools` from) - *not* the project directory.

```text
usage: aoctools init_day [-h] [--root-path [ROOT_PATH]] [--year YEAR]
                         [--skip-bootstrap] [--skip-download]
                         [--session-cookie SESSION_COOKIE]
                         day

positional arguments:
  day                   aoc challenge day

optional arguments:
  -h, --help            show this help message and exit
  --root-path [ROOT_PATH]
                        the root project directory; defaults to the current
                        working directory
  --year YEAR           aoc challenge year; defaults to the project year
  --skip-bootstrap      don't generate python boilerplate
  --skip-download       don't download the challenge input data
  --session-cookie SESSION_COOKIE
                        an AOC login session cookie; defaults to the
                        environment variable AOC_SESSION_COOKIE
```

If you want to generate boilerplate for the challenge day without downloading
the day's input file, pass `--skip-download` to the `aoctools init_day`
command; you can download the day's input file later by passing
`--skip-bootstrap`; NB: the `init_day` command will not clobber existing
python files, so running it twice without passing `--skip-bootstrap` will fail.

### Step 3: Hack

Bootstrapping will generate a new module under the root `aoc` module named after
the freshly bootstrapped day. For example, running `aoctools init_day 1` will
create a file named `aoc/d01/main.py` containing:

```python
from typing import IO

def p_1(input_file: IO,
        debug=False): # pylint: disable=unused-argument
    pass


def p_2(input_file: IO,
        debug=False): # pylint: disable=unused-argument
    pass

```

Filling in `p_1` and `p_2` is where you come in; `aoctools` requires that
you return a (stringifiable) value if you want to use the built-in solution
printer and regression test framework, but there are no restrictions beyond
that.

Running your solution with `aoctools` will result in `p_1` or `p_2` being
called with a reference to the input file; semantically, it's the same as if
you had written:

```python
import aoc.d01

if __name__ == '__main__':
    with open('data/d01/input.txt', 'r', encoding='utf8') as input_file:
        aoc.d01.p_1(input_file, False) # or True
```

and run the file from the root of your project directory. The `debug` variable
is set via the `cli` and makes it easy to control print output:

```python
def p_1(input_file: IO, debug=False):
    v_1 = 1
    v_2 = 2

    if debug:
        print(f"v_1 + v_2 = {v_1} + {v_2} = {v_1 + v_2}")

    return v_1 + v_2
```

### Step 4: Run your solution

```text
usage: aoctools run [-h] [--root-path [ROOT_PATH]] [--debug] day {1,2}

positional arguments:
  day                   aoc challenge day
  {1,2}                 the challenge part to run

optional arguments:
  -h, --help            show this help message and exit
  --root-path [ROOT_PATH]
                        the root project directory
  --debug               print debug info
```

As an example, you can run Day 1, Pt 1 from your root project directory by
invoking:

```text
aoctools run 1 1

solution to day 1, part 1: xxxx
```

### Step 5 (Optional): Regression tests & Code Quality

Once you identify a solution you can populate the automatically generated
regression tests under `tests/aoc/test_d*`:

```python
import aoc.d01

from tests.aoc.test_base import BaseTestCase


class TestAll(BaseTestCase):
    def test_part_one(self):
        self.run_aoc_part(1, CHANGEME, aoc.d01.p_1)

    def test_part_two(self):
        self.run_aoc_part(1, CHANGEME, aoc.d01.p_2)
```

Running `make test` from the root project directory will run all regression
tests.

Similarly, running `make lint` will type lint and type check your code and
tests with both `pylint` and `mypy`.


