Metadata-Version: 2.1
Name: anchovy
Version: 1.0.1
Summary: A minimal, unopinionated file processing engine intended for static website generation.
Author-email: Daniel Foerster <pydsigner@gmail.com>
License: Apache-2.0
Project-URL: Source, https://github.com/pydsigner/anchovy
Keywords: static,website,generation,html,css,template
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Pre-processors
Classifier: Topic :: Text Processing :: Markup
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: all
Requires-Dist: anchovy[base] ; extra == 'all'
Provides-Extra: base
Requires-Dist: anchovy[web] ; extra == 'base'
Requires-Dist: anchovy[include] ; extra == 'base'
Requires-Dist: anchovy[pretty] ; extra == 'base'
Provides-Extra: cq
Requires-Dist: anchovy[all] ; extra == 'cq'
Requires-Dist: tqdm >=4.65.0 ; extra == 'cq'
Requires-Dist: minify-html >=0.11.1 ; extra == 'cq'
Requires-Dist: pylint ; extra == 'cq'
Requires-Dist: pyright ; extra == 'cq'
Requires-Dist: pytest ; extra == 'cq'
Requires-Dist: pytest-cov ; extra == 'cq'
Provides-Extra: css
Requires-Dist: anchovy-css >=0.1.1 ; extra == 'css'
Provides-Extra: include
Requires-Dist: requests >=2.31.0 ; extra == 'include'
Requires-Dist: anchovy[toml] ; extra == 'include'
Provides-Extra: jinja
Requires-Dist: Jinja2 >=3.1.2 ; extra == 'jinja'
Provides-Extra: markdown
Requires-Dist: anchovy[jinja] ; extra == 'markdown'
Requires-Dist: anchovy[toml] ; extra == 'markdown'
Requires-Dist: anchovy[yaml] ; extra == 'markdown'
Requires-Dist: markdown-it-py >=3.0.0 ; extra == 'markdown'
Requires-Dist: mdit-py-plugins >=0.4.0 ; extra == 'markdown'
Requires-Dist: Pygments >=2.12.0 ; extra == 'markdown'
Provides-Extra: minify
Requires-Dist: lightningcss <1.0,>=0.1.1 ; extra == 'minify'
Requires-Dist: minify-html-onepass >=0.11.1 ; extra == 'minify'
Requires-Dist: tdewolff-minify >=2.20.6 ; (sys_platform != "darwin") and extra == 'minify'
Provides-Extra: pillow
Requires-Dist: Pillow >=9.2.0 ; extra == 'pillow'
Provides-Extra: pretty
Requires-Dist: rich >=12.5.1 ; extra == 'pretty'
Provides-Extra: toml
Requires-Dist: tomli >=2.0.1 ; (python_version < "3.11") and extra == 'toml'
Provides-Extra: web
Requires-Dist: anchovy[markdown] ; extra == 'web'
Requires-Dist: anchovy[css] ; extra == 'web'
Requires-Dist: anchovy[pillow] ; extra == 'web'
Requires-Dist: anchovy[minify] ; extra == 'web'
Provides-Extra: yaml
Requires-Dist: ruamel.yaml >=0.18.5 ; extra == 'yaml'

[![PyPI - Project Version](https://img.shields.io/pypi/v/anchovy)](https://pypi.org/project/anchovy)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/anchovy)](https://pypi.org/project/anchovy)
[![GitHub - Project License](https://img.shields.io/github/license/pydsigner/anchovy)](https://github.com/pydsigner/anchovy)
[![GitHub - Code Size](https://img.shields.io/github/languages/code-size/pydsigner/anchovy)](https://github.com/pydsigner/anchovy)
[![codecov](https://codecov.io/gh/pydsigner/anchovy/graph/badge.svg?token=A8WRBWO3JG)](https://codecov.io/gh/pydsigner/anchovy)

# Anchovy

Anchovy is a minimal, unopinionated file-processing framework equipped with a
complete static website generation toolkit.

* **Minimal:** Anchovy’s core is around a thousand lines of code and has no
  mandatory dependencies. Plus, Anchovy can be used for real projects with just
  a few pip-installable extras, even if you want to preprocess CSS.

* **Unopinionated:** Anchovy offers a set of components which can be easily
  configured to your site’s exact requirements, without tediously ripping out
  or overriding entrenched behaviors. Anchovy does not assume you are building
  a blog or that you wish to design your templates in a specific way. You can
  even build things that aren’t websites! Plus, Anchovy operates on files, so
  it’s simple to integrate tools like imagemagick, dart-sass, or less.js if you
  need them.

* **Complete:** Anchovy comes with a dependency auditing system, allowing you
  to grab any component you want without installing anything but Anchovy and
  find out what you *will* need to run your build. Choose from a wealth of
  Steps, Anchovy’s modular file processors, for everything from rendering Jinja
  templates and minifying CSS to unpacking archives and thumbnailing images.
  Plus, add a few extra parameters or lines of configuration to get automatic
  intelligent minimum builds based on input checksums, and get a reproducible
  run artifact to boot— even if you want to fetch HTTP resources or write your
  own Steps. Iterate quickly by launching a lightweight development-grade web
  server once the build is complete.

## Installation

Anchovy has no essential prerequisites and can be installed with
`pip install anchovy` to get just the framework and a few built-in components,
but for typical usage `pip install anchovy[base]` is recommended. This will
pull in support for Jinja2 templating, markdown, minification, and Anchovy’s
CSS preprocessor. A full list of available extras may be found in the
[pyproject.toml](https://github.com/pydsigner/anchovy/blob/master/pyproject.toml) file.

Alternatively, Anchovy may be installed directly from source with
`pip install git+https://github.com/pydsigner/anchovy` or the corresponding
`pip install git+https://github.com/pydsigner/anchovy#egg=anchovy[base]`.

## Command Line Usage

Anchovy operates on config files written in Python, or even modules directly.

* `python -m anchovy -h`
* `anchovy -m mypackage.anchovyconf -o ../release/`
* `python -m anchovy mysite/anchovy_site.py -- -h`

### Show Me

Run `anchovy examples/code_index.py -s -p 8080`, then open a browser to
localhost:8080 (or click the link in the console). This example offers the most
extensive demonstration of Anchovy’s functionality as of version 1.0.

### What’s the Baseline?

Here’s minimal example performing about what the `staticjinja` markdown example
offers:

```python
from pathlib import Path

from anchovy import (
    DirectCopyStep,
    InputBuildSettings,
    JinjaMarkdownStep,
    OutputDirPathCalc,
    REMatcher,
    Rule,
)


# Optional, and can be overridden with CLI arguments.
SETTINGS = InputBuildSettings(
    input_dir=Path('site'),
    working_dir=Path('working'),
    output_dir=Path('build'),
    custody_cache=Path('build-cache.json'),
)
RULES = [
    # Ignore dotfiles found in either the input_dir or the working dir.
    Rule(
        (
            REMatcher(r'(.*/)*\..*', parent_dir='input_dir')
            | REMatcher(r'(.*/)*\..*', parent_dir='working_dir')
        ),
        None
    ),
    # Render markdown files, then stop processing them.
    Rule(
        REMatcher(r'.*\.md'),
        [OutputDirPathCalc('.html'), None],
        JinjaMarkdownStep()
    ),
    # Copy everything else in static/ directories through.
    Rule(
        REMatcher(r'(.*/)*static/.*', parent_dir='input_dir'),
        OutputDirPathCalc(),
        DirectCopyStep()
    ),
]
```

This example is very simple, but it’s legitimately enough to start with for a
small website, and offers an advantage over other minimal frameworks by putting
additional batteries within an arm’s reach. If we stored the configuration in
`config.py` and added a raw site like this:
```
site/
    static/
        styles.css
        toolbar.js
    base.jinja.html
    index.md
    about.md
    contact.md
```
 `python -m anchovy config.py` would produce output like this:
```
output/
    static/
        styles.css
        toolbar.js
    index.html
    about.html
    contact.html
```

This example can be found in runnable form as [examples/basic_site.py](https://github.com/pydsigner/anchovy/blob/master/examples/basic_site.py)
in the source distribution. Available command line arguments can be seen by
passing `-h`: `python -m anchovy examples/basic_site.py -- -h`. The `--` is
required because `anchovy` itself also accepts the flag.

## Programmatic Usage

Anchovy is very usable from the command line, but projects desiring to
customize behavior, for example by running tasks before or after pipeline
execution, may utilize `anchovy.cli.run_from_rules()`:

```python
import time
from pathlib import Path

from anchovy.cli import run_from_rules
from anchovy.core import Context

from my_site.config import SETTINGS, RULES


class MyContext(Context):
    def find_inputs(path: Path):
        # Only process files modified in the last hour.
        hour_ago = time.time() - 3600
        for candidate in super().find_inputs(path):
            if candidate.stat().st_mtime > hour_ago:
                yield candidate


def main():
    print('Pretending to run pre-pipeline tasks...')
    run_from_rules(SETTINGS, RULES, context_cls=MyContext)
    print('Pretending to run post-pipeline tasks...')


if __name__ == '__main__':
    main()
```
