Metadata-Version: 2.4
Name: stapel-categories
Version: 0.5.5
Summary: Category tree for the Stapel framework
License: MIT
Project-URL: Homepage, https://github.com/usestapel/stapel-categories
Project-URL: Repository, https://github.com/usestapel/stapel-categories
Project-URL: Documentation, https://github.com/usestapel/stapel-categories#readme
Project-URL: Changelog, https://github.com/usestapel/stapel-categories/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/usestapel/stapel-categories/issues
Keywords: django,stapel,categories
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: stapel-core<1.0,>=0.26.0
Requires-Dist: stapel-attributes<0.5,>=0.4
Requires-Dist: django-treenode<0.24,>=0.23
Requires-Dist: drf-spectacular>=0.27
Provides-Extra: all
Dynamic: license-file

<!-- Generated by stapel-readme from docs/readme.md + docs/*.json. Do not edit this file; edit docs/readme.md and re-run `make readme`. -->

# stapel-categories

[![CI](https://img.shields.io/github/actions/workflow/status/usestapel/stapel-categories/ci.yml?branch=main&logo=github&label=CI)](https://github.com/usestapel/stapel-categories/actions/workflows/ci.yml?query=branch%3Amain)
[![coverage](https://img.shields.io/codecov/c/github/usestapel/stapel-categories?branch=main&logo=codecov&label=coverage)](https://app.codecov.io/gh/usestapel/stapel-categories)
[![pypi](https://img.shields.io/pypi/v/stapel-categories?logo=pypi&logoColor=white&label=pypi)](https://pypi.org/project/stapel-categories/)
[![downloads](https://static.pepy.tech/badge/stapel-categories/month)](https://pepy.tech/project/stapel-categories)
[![python](https://img.shields.io/pypi/pyversions/stapel-categories?logo=python&logoColor=white)](https://pypi.org/project/stapel-categories/)
[![license](https://img.shields.io/github/license/usestapel/stapel-categories)](https://github.com/usestapel/stapel-categories/blob/main/LICENSE)
[![llms.txt](https://img.shields.io/badge/llms.txt-blue)](https://github.com/usestapel/stapel-categories/blob/main/docs/llms.txt)

> Category tree with typed features: a hierarchical category tree (django-treenode) and a parallel feature tree whose typed config is validated by stapel-attributes, an ordered category<->feature M2M, feature inheritance, and a feature-editor lifecycle (keep/add/edit/inherit/remove/create/replace) with optimistic-concurrency apply over a category subtree.

Part of the [Stapel framework](https://github.com/usestapel) — composable Django apps that deploy as a monolith or as microservices without changing module code.

## Install

```bash
pip install stapel-categories
```

## At a glance

| Fact | Value |
|---|---|
| Version | `0.5.5` |
| Python | `>=3.11` (3.11, 3.12, 3.13, 3.14) |
| HTTP operations | 27 |
| Config axes | 1 |
| Usage surface | 18 |
| Extension points | 4 |
| Fleet dependencies | [`stapel-attributes`](https://github.com/usestapel/stapel-attributes) · [`stapel-core`](https://github.com/usestapel/stapel-core) |

## Documentation

[capabilities.json](https://github.com/usestapel/stapel-categories/blob/main/docs/capabilities.json) · [llms.txt (for agents)](https://github.com/usestapel/stapel-categories/blob/main/docs/llms.txt)

## What this is

A hierarchical **category** tree (django-treenode) and a parallel **feature**
tree whose typed `config` is validated by
[stapel-attributes](https://github.com/usestapel/stapel-attributes). Categories
own the tree structure, feature inheritance, the ordered category↔feature M2M,
and the feature-editor lifecycle; the attribute *engine* (types, config/DTO/DAO
validation, polymorphic serializers, admin widgets) lives in stapel-attributes
and is imported, never re-implemented.

## Quick start

```python
INSTALLED_APPS = [
    # ...
    "treenode",            # django-treenode (tree-cache signals)
    "stapel_categories",
]

# urls.py — the host chooses the prefix
path("categories/", include("stapel_categories.urls"))
```

`stapel-attributes` is an imported library (no app to install); its config
editor ships static assets, so run `collectstatic` if you use the admin.

## Settings

All configuration lives in the `STAPEL_CATEGORIES` namespace (dict setting,
flat setting, or env var — resolved lazily):

| Key | Default | Meaning |
|---|---|---|
| `CAROUSEL_CACHE_TIMEOUT` | `300` | Seconds the `carousel` response is cached. |
| `FEATURE_DISPLAY_CACHE_TIMEOUT` | `60` | Seconds an admin feature display label is memoized. |
| `DISPLAY_TRANSLATOR` | `stapel_categories.translation.identity_translator` | Dotted path `(key)->str` for rendering translation keys (default: identity). |

## comm surface

| Kind | Name | Contract |
|---|---|---|
| Function | `categories.features` | `{"category_id": int}` -> `{"category_id", "revision", "features":[{id,slug,name,mandatory,config}]}` — resolved schema (own + inherited), cacheable by `revision` |
| Action (emit) | `category.changed` | `{"category_id": int, "revision": int}` on any category/feature mutation — for downstream cache invalidation |

`categories.features` lets stapel-listings validate attribute values against a
category's schema without importing this module.

## Extension points

See [MODULE.md](https://github.com/usestapel/stapel-categories/blob/main/MODULE.md) — the agent-facing map of every fork-free seam
(settings, serializer seams, comm surface, feature-editor actions, admin-UI
pointer to stapel-attributes).

## Development

```bash
pip install -e . && pip install pytest pytest-django ruff
./setup-hooks.sh
pytest tests/
```

## License

MIT — see [LICENSE](https://github.com/usestapel/stapel-categories/blob/main/LICENSE).

---

<sub>This page is assembled by `stapel-readme` from `docs/readme.md` plus the contract artifacts in `docs/`. Edit the prose in `docs/readme.md`; the badges, facts and links above and below it are generated — do not hand-edit `README.md`.</sub>
