Metadata-Version: 2.4
Name: chinese_history_toolkits
Version: 0.2.0
Summary: Bidirectional Chinese-history time mapping with a transparent cleaning pipeline (import as `chhiskit`).
Project-URL: Homepage, https://github.com/SongshGeoLab/chinese_history_toolkits
Project-URL: Documentation, https://songshgeolab.github.io/chinese_history_toolkits/
Project-URL: Source, https://github.com/SongshGeoLab/chinese_history_toolkits
Project-URL: Issues, https://github.com/SongshGeoLab/chinese_history_toolkits/issues
Author-email: SongshGeo <songshgeo@gmail.com>
License: MIT
License-File: LICENSE
Requires-Python: <3.14,>=3.10
Requires-Dist: future-annotations>=1.0.0
Requires-Dist: pandas>=2.0
Requires-Dist: typing-extensions>=4.12.2
Provides-Extra: dev
Requires-Dist: allure-pytest>=2.13.0; extra == 'dev'
Requires-Dist: flake8>=6.0.0; extra == 'dev'
Requires-Dist: interrogate>=1.7.0; extra == 'dev'
Requires-Dist: ipykernel>=6.21.2; extra == 'dev'
Requires-Dist: ipywidgets>=8.1.5; extra == 'dev'
Requires-Dist: isort>=5.12.0; extra == 'dev'
Requires-Dist: nbstripout>=0.6.1; extra == 'dev'
Requires-Dist: pre-commit-hooks>=4.4.0; extra == 'dev'
Requires-Dist: pydocstyle>=6.3.0; extra == 'dev'
Requires-Dist: pytest-mpl>=0.17.0; extra == 'dev'
Requires-Dist: pytest>=7.2.1; extra == 'dev'
Requires-Dist: snakeviz>=2.2.0; extra == 'dev'
Requires-Dist: tox>=4.0.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mike>=2.0.0; extra == 'docs'
Requires-Dist: mkdocs-awesome-pages-plugin>=2.8.0; extra == 'docs'
Requires-Dist: mkdocs-bibtex>=2.8.16; extra == 'docs'
Requires-Dist: mkdocs-callouts>=1.9.0; extra == 'docs'
Requires-Dist: mkdocs-exclude>=1.0.2; extra == 'docs'
Requires-Dist: mkdocs-ezlinks-plugin>=0.1.14; extra == 'docs'
Requires-Dist: mkdocs-git-authors-plugin>=0.7.0; extra == 'docs'
Requires-Dist: mkdocs-git-revision-date-localized-plugin>=1.2.0; extra == 'docs'
Requires-Dist: mkdocs-glightbox>=0.3.2; extra == 'docs'
Requires-Dist: mkdocs-jupyter>=0.24.1; extra == 'docs'
Requires-Dist: mkdocs-macros-plugin>=0.7.0; extra == 'docs'
Requires-Dist: mkdocs-material>=9.1.6; extra == 'docs'
Requires-Dist: mkdocs-minify-plugin>=0.6.4; extra == 'docs'
Requires-Dist: mkdocs-redirects>=1.2.0; extra == 'docs'
Requires-Dist: mkdocs-static-i18n>=1.2; extra == 'docs'
Requires-Dist: mkdocs>=1.4.2; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
Description-Content-Type: text/markdown

<div align="center">

# 🏛️ Chinese History Toolkits

**Map any year to its Chinese dynasty / reign-era / epoch — and back.**

[English](README.md) · [中文](README.zh.md) · [Online Docs](https://songshgeolab.github.io/chinese_history_toolkits/)

[![Python](https://img.shields.io/badge/Python-3.10%E2%80%933.13-blue)](https://www.python.org/)
[![License](https://img.shields.io/badge/License-MIT-green)](LICENSE)
[![Docs](https://img.shields.io/badge/docs-mkdocs--material-purple)](https://songshgeolab.github.io/chinese_history_toolkits/)
[![Tests](https://img.shields.io/badge/tests-125%20passing-brightgreen)]()
[![Doc coverage](https://img.shields.io/badge/docstrings-100%25-brightgreen)]()

</div>

---

A typed, dependency-light Python API for Chinese historical chronology: look up any 年号 / 朝代 / 历史时期 by name or by year, from the Paleolithic through 清.

## ✨ Features

- 🔁 **Two-way lookup** — name → `(begin, end)` years; year → list of all parallel polities.
- 🪨 **Full timeline** — 旧石器 / 新石器 prehistoric brackets through 清.
- 📚 **Selectable chronology** — 上古 dating is contested scholarship, so pick the source you trust: 上海图书馆, 夏商周断代工程, or 万国鼎《中国历史纪年表》.
- 🧭 **Disambiguated** — reused names resolve correctly (`夏(窦建德)` ≠ 上古 `夏`), and an ambiguous 年号 raises rather than guessing.
- 🌐 **Alias-friendly** — pass `aliases={"新石器": {"Neolithic", "Neo"}}` to accept foreign-language input.
- ⚡ **Lightweight** — only `pandas` at runtime; data ships with the package, no network needed.

## 🚀 Quickstart

```bash
# From PyPI — distribution name is `chinese_history_toolkits`
pip install chinese_history_toolkits

# Or from source
git clone https://github.com/SongshGeoLab/chinese_history_toolkits.git
cd chinese_history_toolkits
uv sync --all-extras
```

> **Note** — the PyPI distribution name is `chinese_history_toolkits` (verbose), but the **import name is the short acronym `chhiskit`** for daily use.

```python
import chhiskit

# Name → years
chhiskit.get_age_from_cultural_period("康熙")                              # → (1662.0, 1722.0)
chhiskit.get_age_from_cultural_period("唐", level="dynasty")               # → (618.0, 907.0)
chhiskit.get_age_from_cultural_period("新石器", level="epoch")             # → (-10000.0, -2070.0)

# Year → matching polities (multiple are normal — 三国, 隋末, etc.)
[m.dynasty_id for m in chhiskit.get_cultural_periods_from_year(250)]
# → ['三国', '吴', '蜀', '魏']

# BP convention (radiocarbon, 1950 reference)
chhiskit.get_age_from_cultural_period("商", level="dynasty", anno_domini=False)
# → (3550.0, 2996.0)

# Foreign aliases
chhiskit.get_age_from_cultural_period(
    "Neolithic", level="epoch",
    aliases={"新石器": {"Neolithic", "Neo"}},
)
# → (-10000.0, -2070.0)
```

## 📚 Choosing a chronology

Scholars disagree about 上古 dating — the disagreement is real scholarship, not
data error — so this library lets you pick rather than deciding for you:

```python
chhiskit.get_age_from_cultural_period("夏", level="epoch")                 # → (-2070.0, ...)  夏商周断代工程 (default)
chhiskit.get_age_from_cultural_period("夏", level="epoch", source="shl")   # → (-1989.0, ...)  上海图书馆
chhiskit.get_age_from_cultural_period("夏", level="epoch", source="wgd")   # → (-2100.0, ...)  万国鼎 1956

chhiskit.set_default_source("shl")   # or set a preference once
chhiskit.list_sources()              # what each source covers
```

Sources overlay the base table and fall back to it where they are silent, so
asking a source for something it never covered warns you rather than quietly
handing you someone else's numbers. See **[Chronology Sources](docs/doc/sources.md)**.

## 📖 Documentation

| | |
|---|---|
| 📖 **[Quick Start](docs/doc/quick-start.md)** | Install + first lookup, 5 minutes |
| 📚 **[API Reference](docs/doc/api-reference.md)** | Every parameter, with worked examples |
| 🗺️ **[Epochs Reference](docs/doc/epochs.md)** | `EPOCH_MAP` + `PREHISTORIC_EPOCHS` |
| 🕰️ **[Chronology Sources](docs/doc/sources.md)** | Which source says what, and how to pick |

Build the site locally:

```bash
make docs       # serve at http://127.0.0.1:8000
make docs-build # static build
```

## 🧪 Development

```bash
make test                       # pytest
pre-commit run --all-files      # black + ruff + flake8 + mypy + interrogate
make tox                        # Python 3.10–3.13 matrix
```

The test file `tests/test_dynasties.py` is the executable spec — 125 cases organized into one class per behavior cluster, each with a docstring explaining what it pins.

How the shipped data is produced, audited and regenerated is documented for maintainers in [`data/dynasties/readme.md`](data/dynasties/readme.md).

## 📄 Data attribution

| Source | Used for |
|---|---|
| [上海图书馆开放数据平台](https://data.library.sh.cn/dynasty/) | Base table — 朝代 / 年号 / 帝王 |
| 夏商周断代工程 (2000) | 上古 chronology (`source="xsz"`, default) |
| 万国鼎《中国历史纪年表》(中华书局, 1956) | 国号 / 朝代 spans (`source="wgd"`) |

Every modification to the upstream data is recorded row-by-row in [`dynasty_drops.md`](data/dynasties/dynasty_drops.md), each with a link back to the source record.

## 🤝 Contributing

PRs welcome. Please:

1. Run `pre-commit run --all-files` and `make test` (must pass).
2. New behavior → new test in `tests/test_dynasties.py` with a docstring describing what it pins.
3. Touching the data? See [`data/dynasties/readme.md`](data/dynasties/readme.md) — regenerated artifacts are committed alongside the change so the diff is its own audit trail.

## 📜 License

MIT — see [LICENSE](LICENSE).

## 👤 Author

**SongshGeo** · [GitHub](https://github.com/SongshGeo) · [Website](https://cv.songshgeo.com/)
