cihai-cli 0.32.0__tar.gz → 0.33.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cihai_cli-0.33.0/.github/contributing.md +26 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.github/workflows/docs.yml +12 -3
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.github/workflows/tests.yml +1 -1
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.gitignore +4 -0
- cihai_cli-0.33.0/.tool-versions +3 -0
- cihai_cli-0.33.0/AGENTS.md +435 -0
- cihai_cli-0.33.0/CHANGES +804 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/PKG-INFO +2 -2
- cihai_cli-0.33.0/conftest.py +18 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/cli/completion.md +6 -6
- cihai_cli-0.33.0/docs/cli/index.md +60 -0
- cihai_cli-0.33.0/docs/conf.py +50 -0
- cihai_cli-0.33.0/docs/index.md +76 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/justfile +3 -3
- cihai_cli-0.33.0/docs/project/code-style.md +31 -0
- cihai_cli-0.33.0/docs/project/contributing.md +28 -0
- cihai_cli-0.33.0/docs/project/index.md +36 -0
- cihai_cli-0.33.0/docs/project/releasing.md +29 -0
- cihai_cli-0.33.0/docs/redirects.txt +2 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/pyproject.toml +40 -37
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/src/cihai_cli/__about__.py +1 -1
- cihai_cli-0.33.0/src/cihai_cli/__init__.py +7 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/src/cihai_cli/_colors.py +6 -0
- cihai_cli-0.33.0/uv.lock +2146 -0
- cihai_cli-0.32.0/.tool-versions +0 -3
- cihai_cli-0.32.0/AGENTS.md +0 -174
- cihai_cli-0.32.0/CHANGES +0 -729
- cihai_cli-0.32.0/docs/_ext/__init__.py +0 -3
- cihai_cli-0.32.0/docs/_ext/argparse_exemplar.py +0 -1278
- cihai_cli-0.32.0/docs/_ext/argparse_lexer.py +0 -429
- cihai_cli-0.32.0/docs/_ext/argparse_roles.py +0 -370
- cihai_cli-0.32.0/docs/_ext/cli_usage_lexer.py +0 -115
- cihai_cli-0.32.0/docs/_ext/conftest.py +0 -15
- cihai_cli-0.32.0/docs/_ext/sphinx_argparse_neo/__init__.py +0 -101
- cihai_cli-0.32.0/docs/_ext/sphinx_argparse_neo/compat.py +0 -271
- cihai_cli-0.32.0/docs/_ext/sphinx_argparse_neo/directive.py +0 -241
- cihai_cli-0.32.0/docs/_ext/sphinx_argparse_neo/nodes.py +0 -564
- cihai_cli-0.32.0/docs/_ext/sphinx_argparse_neo/parser.py +0 -627
- cihai_cli-0.32.0/docs/_ext/sphinx_argparse_neo/renderer.py +0 -521
- cihai_cli-0.32.0/docs/_ext/sphinx_argparse_neo/utils.py +0 -42
- cihai_cli-0.32.0/docs/_static/css/argparse-highlight.css +0 -274
- cihai_cli-0.32.0/docs/_static/css/custom.css +0 -20
- cihai_cli-0.32.0/docs/_templates/layout.html +0 -45
- cihai_cli-0.32.0/docs/_templates/sidebar/projects.html +0 -69
- cihai_cli-0.32.0/docs/cli/index.md +0 -36
- cihai_cli-0.32.0/docs/conf.py +0 -231
- cihai_cli-0.32.0/docs/index.md +0 -26
- cihai_cli-0.32.0/docs/redirects.txt +0 -2
- cihai_cli-0.32.0/src/cihai_cli/__init__.py +0 -1
- cihai_cli-0.32.0/tests/docs/__init__.py +0 -3
- cihai_cli-0.32.0/tests/docs/_ext/__init__.py +0 -3
- cihai_cli-0.32.0/tests/docs/_ext/conftest.py +0 -11
- cihai_cli-0.32.0/tests/docs/_ext/sphinx_argparse_neo/__init__.py +0 -3
- cihai_cli-0.32.0/tests/docs/_ext/sphinx_argparse_neo/conftest.py +0 -237
- cihai_cli-0.32.0/tests/docs/_ext/sphinx_argparse_neo/test_compat.py +0 -330
- cihai_cli-0.32.0/tests/docs/_ext/sphinx_argparse_neo/test_nodes.py +0 -259
- cihai_cli-0.32.0/tests/docs/_ext/sphinx_argparse_neo/test_parser.py +0 -524
- cihai_cli-0.32.0/tests/docs/_ext/sphinx_argparse_neo/test_renderer.py +0 -498
- cihai_cli-0.32.0/tests/docs/_ext/sphinx_argparse_neo/test_utils.py +0 -72
- cihai_cli-0.32.0/tests/docs/_ext/test_argparse_exemplar.py +0 -1020
- cihai_cli-0.32.0/tests/docs/_ext/test_argparse_lexer.py +0 -798
- cihai_cli-0.32.0/tests/docs/_ext/test_argparse_roles.py +0 -442
- cihai_cli-0.32.0/tests/docs/_ext/test_cli_usage_lexer.py +0 -358
- cihai_cli-0.32.0/uv.lock +0 -1894
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.codecov.yml +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.cursor/rules/avoid-debug-loops.mdc +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.cursor/rules/dev-loop.mdc +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.cursor/rules/git-commits.mdc +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.cursor/rules/notes-llms-txt.mdc +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.github/dependabot.yml +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.prettierrc +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.python-version +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.tmuxp.yaml +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.vim/coc-settings.json +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/.windsurfrules +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/CLAUDE.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/LICENSE +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/MANIFEST.in +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/MIGRATION +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/README.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/favicon.ico +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/cihai.svg +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-128x128.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-144x144.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-152x152.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-192x192.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-384x384.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-512x512-centered.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-512x512.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-72x72.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/_static/img/icons/icon-96x96.png +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/api.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/cli/info.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/cli/reverse.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/history.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/manifest.json +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/migration.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/docs/quickstart.md +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/justfile +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/src/cihai_cli/_formatter.py +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/src/cihai_cli/cli.py +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/src/cihai_cli/py.typed +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/__init__.py +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/conftest.py +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_DictionaryIndices.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_DictionaryLikeData.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_IRGSources.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_NumericValues.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_OtherMappings.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_RadicalStrokeCounts.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_Readings.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/Unihan_Variants.txt +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/fixtures/test_config.yml +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tests/test_cli.py +0 -0
- {cihai_cli-0.32.0 → cihai_cli-0.33.0}/tox.ini +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
When contributing to this repository, please first discuss the change you wish to make via issue,
|
|
4
|
+
email, or any other method with the maintainers of this repository before making a change.
|
|
5
|
+
|
|
6
|
+
See [AGENTS.md](../AGENTS.md) for coding standards and development workflow.
|
|
7
|
+
|
|
8
|
+
## Pull Request Process
|
|
9
|
+
|
|
10
|
+
1. **Format and lint**: `uv run ruff format .` then `uv run ruff check . --fix --show-fixes`
|
|
11
|
+
2. **Type check**: `uv run mypy`
|
|
12
|
+
3. **Test**: `uv run pytest` — all tests must pass before submitting
|
|
13
|
+
4. **Document**: Update docs if your change affects the public interface
|
|
14
|
+
5. You may merge the Pull Request once you have the sign-off of one other developer. If you
|
|
15
|
+
do not have permission to do that, you may request a reviewer to merge it for you.
|
|
16
|
+
|
|
17
|
+
## Decorum
|
|
18
|
+
|
|
19
|
+
- Participants will be tolerant of opposing views.
|
|
20
|
+
- Participants must ensure that their language and actions are free of personal
|
|
21
|
+
attacks and disparaging personal remarks.
|
|
22
|
+
- When interpreting the words and actions of others, participants should always
|
|
23
|
+
assume good intentions.
|
|
24
|
+
- Behaviour which can be reasonably considered harassment will not be tolerated.
|
|
25
|
+
|
|
26
|
+
Based on [Ruby's Community Conduct Guideline](https://www.ruby-lang.org/en/conduct/)
|
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
- uses: actions/checkout@v6
|
|
21
21
|
|
|
22
22
|
- name: Filter changed file paths to outputs
|
|
23
|
-
uses: dorny/paths-filter@
|
|
23
|
+
uses: dorny/paths-filter@v4.0.1
|
|
24
24
|
id: changes
|
|
25
25
|
with:
|
|
26
26
|
filters: |
|
|
@@ -51,7 +51,7 @@ jobs:
|
|
|
51
51
|
run: uv sync --all-extras --dev
|
|
52
52
|
|
|
53
53
|
- name: Install just
|
|
54
|
-
uses: extractions/setup-just@
|
|
54
|
+
uses: extractions/setup-just@v4
|
|
55
55
|
|
|
56
56
|
- name: Print python versions
|
|
57
57
|
if: env.PUBLISH == 'true'
|
|
@@ -59,6 +59,15 @@ jobs:
|
|
|
59
59
|
python -V
|
|
60
60
|
uv run python -V
|
|
61
61
|
|
|
62
|
+
- name: Cache sphinx fonts
|
|
63
|
+
if: env.PUBLISH == 'true'
|
|
64
|
+
uses: actions/cache@v5
|
|
65
|
+
with:
|
|
66
|
+
path: ~/.cache/sphinx-fonts
|
|
67
|
+
key: sphinx-fonts-${{ hashFiles('docs/conf.py') }}
|
|
68
|
+
restore-keys: |
|
|
69
|
+
sphinx-fonts-
|
|
70
|
+
|
|
62
71
|
- name: Build documentation
|
|
63
72
|
if: env.PUBLISH == 'true'
|
|
64
73
|
run: |
|
|
@@ -66,7 +75,7 @@ jobs:
|
|
|
66
75
|
|
|
67
76
|
- name: Configure AWS Credentials
|
|
68
77
|
if: env.PUBLISH == 'true'
|
|
69
|
-
uses: aws-actions/configure-aws-credentials@
|
|
78
|
+
uses: aws-actions/configure-aws-credentials@v6
|
|
70
79
|
with:
|
|
71
80
|
role-to-assume: ${{ secrets.CIHAI_CLI_DOCS_ROLE_ARN }}
|
|
72
81
|
aws-region: us-east-1
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI agents (Cursor, Claude Code, Copilot, etc.) working in this repository.
|
|
4
|
+
|
|
5
|
+
## CRITICAL REQUIREMENTS
|
|
6
|
+
|
|
7
|
+
### Test Success
|
|
8
|
+
- ALL tests must pass (unit, doctest, lint, type checks) before declaring work complete.
|
|
9
|
+
- Do not describe code as "working" if any test fails.
|
|
10
|
+
- Fix regressions rather than disabling or skipping tests unless explicitly approved.
|
|
11
|
+
|
|
12
|
+
## Project Overview
|
|
13
|
+
|
|
14
|
+
gp-libs is the shared tooling stack used across the git-pull ecosystem. This repository, `cihai-cli`, is a command-line interface built on top of the `cihai` library to explore the Unihan (CJK) character database. Key abilities:
|
|
15
|
+
- Lookup CJK characters with `cihai info <char>` and YAML-formatted output.
|
|
16
|
+
- Reverse search definitions with `cihai reverse <term>`.
|
|
17
|
+
- Bootstraps and queries the Unihan dataset via `cihai` / `unihan-etl`.
|
|
18
|
+
- Provides a small, typed argparse-based CLI (`src/cihai_cli/cli.py`) exposed as the `cihai` entry point.
|
|
19
|
+
|
|
20
|
+
## Development Environment
|
|
21
|
+
|
|
22
|
+
This project uses:
|
|
23
|
+
- Python 3.10+
|
|
24
|
+
- [uv](https://github.com/astral-sh/uv) for dependency and task execution
|
|
25
|
+
- [ruff](https://github.com/astral-sh/ruff) for linting/formatting
|
|
26
|
+
- [mypy](https://github.com/python/mypy) with strict settings
|
|
27
|
+
- [pytest](https://docs.pytest.org/) (+ doctests) for testing
|
|
28
|
+
- [gp-libs](https://github.com/gp-libs/gp-libs) for shared docs/testing helpers
|
|
29
|
+
- Sphinx (Furo) for documentation
|
|
30
|
+
|
|
31
|
+
## Common Commands
|
|
32
|
+
|
|
33
|
+
### Setup
|
|
34
|
+
```bash
|
|
35
|
+
# Install dependencies (editable)
|
|
36
|
+
uv pip install --editable .
|
|
37
|
+
uv pip sync
|
|
38
|
+
|
|
39
|
+
# Install with dev extras
|
|
40
|
+
uv pip install --editable . -G dev
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Tests
|
|
44
|
+
```bash
|
|
45
|
+
just test # or: uv run pytest
|
|
46
|
+
uv run pytest tests/test_cli.py # single file
|
|
47
|
+
uv run pytest tests/test_cli.py::test_info_command # single test
|
|
48
|
+
|
|
49
|
+
just start # run tests then watch with pytest-watcher
|
|
50
|
+
uv run ptw . # standalone watcher (doctests enabled by default)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Linting & Types
|
|
54
|
+
```bash
|
|
55
|
+
just ruff # uv run ruff check .
|
|
56
|
+
just ruff-format # uv run ruff format .
|
|
57
|
+
uv run ruff check . --fix --show-fixes
|
|
58
|
+
|
|
59
|
+
just mypy # strict type checking
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Documentation
|
|
63
|
+
```bash
|
|
64
|
+
just build-docs # build Sphinx HTML in docs/_build
|
|
65
|
+
just start-docs # autobuild + livereload
|
|
66
|
+
just design-docs # update CSS/JS assets
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Workflow (recommended)
|
|
70
|
+
1) `uv run ruff format .`
|
|
71
|
+
2) `uv run pytest`
|
|
72
|
+
3) `uv run ruff check . --fix --show-fixes`
|
|
73
|
+
4) `uv run mypy`
|
|
74
|
+
5) `uv run pytest` (verify clean)
|
|
75
|
+
|
|
76
|
+
## Code Architecture (quick map)
|
|
77
|
+
- `src/cihai_cli/cli.py`: argparse entrypoint, implements `info` and `reverse` commands, logging setup.
|
|
78
|
+
- `src/cihai_cli/__about__.py`: package metadata (`__version__`).
|
|
79
|
+
- Tests: `tests/` (unit) plus doctests in `src/` and `docs/`.
|
|
80
|
+
- Docs: `docs/` Sphinx project (Furo theme).
|
|
81
|
+
|
|
82
|
+
## Testing Strategy
|
|
83
|
+
- Pytest with doctests enabled (`addopts` in `pyproject.toml`).
|
|
84
|
+
- Prefer real `cihai` / `unihan_etl` integration over heavy mocking; reuse fixtures where present.
|
|
85
|
+
- Watch mode: `uv run ptw .` (used in `just start`).
|
|
86
|
+
- Coverage via `pytest-cov`; configuration in `pyproject.toml`.
|
|
87
|
+
- Prefer fixtures over mocks (`server`, `session`, etc. when available); use `tmp_path` over `tempfile`, `monkeypatch` over `unittest.mock`.
|
|
88
|
+
|
|
89
|
+
## Coding Standards
|
|
90
|
+
- `from __future__ import annotations` required; enforced by ruff.
|
|
91
|
+
- Namespace imports for stdlib/typing (`import typing as t`); third-party packages may use `from X import Y`.
|
|
92
|
+
- Docstrings follow NumPy style (see `tool.ruff.lint.pydocstyle`).
|
|
93
|
+
- Python target version: 3.10 (`tool.ruff.target-version`).
|
|
94
|
+
- Keep CLI output human-friendly YAML; avoid breaking existing flags/args.
|
|
95
|
+
- Doctests: keep concise, narrative Examples blocks; move complex flows to `tests/examples/`.
|
|
96
|
+
|
|
97
|
+
## Logging Standards
|
|
98
|
+
|
|
99
|
+
These rules guide future logging changes; existing code may not yet conform.
|
|
100
|
+
|
|
101
|
+
### Logger setup
|
|
102
|
+
|
|
103
|
+
- Use `logging.getLogger(__name__)` in every module
|
|
104
|
+
- Add `NullHandler` in library `__init__.py` files
|
|
105
|
+
- Never configure handlers, levels, or formatters in library code — that's the application's job
|
|
106
|
+
|
|
107
|
+
### Structured context via `extra`
|
|
108
|
+
|
|
109
|
+
Pass structured data on every log call where useful for filtering, searching, or test assertions.
|
|
110
|
+
|
|
111
|
+
**Core keys** (stable, scalar, safe at any log level):
|
|
112
|
+
|
|
113
|
+
| Key | Type | Context |
|
|
114
|
+
|-----|------|---------|
|
|
115
|
+
| `unihan_field` | `str` | UNIHAN field name |
|
|
116
|
+
| `unihan_source_file` | `str` | source data file path |
|
|
117
|
+
| `unihan_record_count` | `int` | records processed |
|
|
118
|
+
| `cihai_command` | `str` | CLI command name |
|
|
119
|
+
|
|
120
|
+
**Heavy/optional keys** (DEBUG only, potentially large):
|
|
121
|
+
|
|
122
|
+
| Key | Type | Context |
|
|
123
|
+
|-----|------|---------|
|
|
124
|
+
| `unihan_stdout` | `list[str]` | subprocess stdout lines (truncate or cap; `%(unihan_stdout)s` produces repr) |
|
|
125
|
+
| `unihan_stderr` | `list[str]` | subprocess stderr lines (same caveats) |
|
|
126
|
+
|
|
127
|
+
Treat established keys as compatibility-sensitive — downstream users may build dashboards and alerts on them. Change deliberately.
|
|
128
|
+
|
|
129
|
+
### Key naming rules
|
|
130
|
+
|
|
131
|
+
- `snake_case`, not dotted; `unihan_` prefix
|
|
132
|
+
- Prefer stable scalars; avoid ad-hoc objects
|
|
133
|
+
- Heavy keys (`unihan_stdout`, `unihan_stderr`) are DEBUG-only; consider companion `unihan_stdout_len` fields or hard truncation (e.g. `stdout[:100]`)
|
|
134
|
+
|
|
135
|
+
### Lazy formatting
|
|
136
|
+
|
|
137
|
+
`logger.debug("msg %s", val)` not f-strings. Two rationales:
|
|
138
|
+
- Deferred string interpolation: skipped entirely when level is filtered
|
|
139
|
+
- Aggregator message template grouping: `"Running %s"` is one signature grouped ×10,000; f-strings make each line unique
|
|
140
|
+
|
|
141
|
+
When computing `val` itself is expensive, guard with `if logger.isEnabledFor(logging.DEBUG)`.
|
|
142
|
+
|
|
143
|
+
### stacklevel for wrappers
|
|
144
|
+
|
|
145
|
+
Increment for each wrapper layer so `%(filename)s:%(lineno)d` and OTel `code.filepath` point to the real caller. Verify whenever call depth changes.
|
|
146
|
+
|
|
147
|
+
### LoggerAdapter for persistent context
|
|
148
|
+
|
|
149
|
+
For objects with stable identity (Dataset, Reader, Exporter), use `LoggerAdapter` to avoid repeating the same `extra` on every call. Lead with the portable pattern (override `process()` to merge); `merge_extra=True` simplifies this on Python 3.13+.
|
|
150
|
+
|
|
151
|
+
### Log levels
|
|
152
|
+
|
|
153
|
+
| Level | Use for | Examples |
|
|
154
|
+
|-------|---------|----------|
|
|
155
|
+
| `DEBUG` | Internal mechanics, data I/O | Field parsing, record transformation steps |
|
|
156
|
+
| `INFO` | Data lifecycle, user-visible operations | Download completed, export finished, database bootstrapped |
|
|
157
|
+
| `WARNING` | Recoverable issues, deprecation, user-actionable config | Missing optional field, deprecated data format |
|
|
158
|
+
| `ERROR` | Failures that stop an operation | Download failed, parse error, database write failed |
|
|
159
|
+
|
|
160
|
+
Config discovery noise belongs in `DEBUG`; only surprising/user-actionable config issues → `WARNING`.
|
|
161
|
+
|
|
162
|
+
### Message style
|
|
163
|
+
|
|
164
|
+
- Lowercase, past tense for events: `"download completed"`, `"parse error"`
|
|
165
|
+
- No trailing punctuation
|
|
166
|
+
- Keep messages short; put details in `extra`, not the message string
|
|
167
|
+
|
|
168
|
+
### Exception logging
|
|
169
|
+
|
|
170
|
+
- Use `logger.exception()` only inside `except` blocks when you are **not** re-raising
|
|
171
|
+
- Use `logger.error(..., exc_info=True)` when you need the traceback outside an `except` block
|
|
172
|
+
- Avoid `logger.exception()` followed by `raise` — this duplicates the traceback. Either add context via `extra` that would otherwise be lost, or let the exception propagate
|
|
173
|
+
|
|
174
|
+
### Testing logs
|
|
175
|
+
|
|
176
|
+
Assert on `caplog.records` attributes, not string matching on `caplog.text`:
|
|
177
|
+
- Scope capture: `caplog.at_level(logging.DEBUG, logger="cihai_cli.cli")`
|
|
178
|
+
- Filter records rather than index by position: `[r for r in caplog.records if hasattr(r, "unihan_field")]`
|
|
179
|
+
- Assert on schema: `record.unihan_record_count == 100` not `"100 records" in caplog.text`
|
|
180
|
+
- `caplog.record_tuples` cannot access extra fields — always use `caplog.records`
|
|
181
|
+
|
|
182
|
+
### Avoid
|
|
183
|
+
|
|
184
|
+
- f-strings/`.format()` in log calls
|
|
185
|
+
- Unguarded logging in hot loops (guard with `isEnabledFor()`)
|
|
186
|
+
- Catch-log-reraise without adding new context
|
|
187
|
+
- `print()` for diagnostics
|
|
188
|
+
- Logging secret env var values (log key names only)
|
|
189
|
+
- Non-scalar ad-hoc objects in `extra`
|
|
190
|
+
- Requiring custom `extra` fields in format strings without safe defaults (missing keys raise `KeyError`)
|
|
191
|
+
|
|
192
|
+
## Documentation Standards
|
|
193
|
+
|
|
194
|
+
### Code Blocks in Documentation
|
|
195
|
+
|
|
196
|
+
When writing documentation (README, CHANGES, docs/), follow these rules for code blocks:
|
|
197
|
+
|
|
198
|
+
**One command per code block.** This makes commands individually copyable. For sequential commands, either use separate code blocks or chain them with `&&` or `;` and `\` continuations (keeping it one logical command).
|
|
199
|
+
|
|
200
|
+
**Put explanations outside the code block**, not as comments inside.
|
|
201
|
+
|
|
202
|
+
Good:
|
|
203
|
+
|
|
204
|
+
Run the tests:
|
|
205
|
+
|
|
206
|
+
```console
|
|
207
|
+
$ uv run pytest
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Run with coverage:
|
|
211
|
+
|
|
212
|
+
```console
|
|
213
|
+
$ uv run pytest --cov
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Bad:
|
|
217
|
+
|
|
218
|
+
```console
|
|
219
|
+
# Run the tests
|
|
220
|
+
$ uv run pytest
|
|
221
|
+
|
|
222
|
+
# Run with coverage
|
|
223
|
+
$ uv run pytest --cov
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Shell Command Formatting
|
|
227
|
+
|
|
228
|
+
These rules apply to shell commands in documentation (README, CHANGES, docs/), **not** to Python doctests.
|
|
229
|
+
|
|
230
|
+
**Use `console` language tag with `$ ` prefix.** This distinguishes interactive commands from scripts and enables prompt-aware copy in many terminals.
|
|
231
|
+
|
|
232
|
+
Good:
|
|
233
|
+
|
|
234
|
+
```console
|
|
235
|
+
$ uv run pytest
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Bad:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
uv run pytest
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Split long commands with `\` for readability.** Each flag or flag+value pair gets its own continuation line, indented. Positional parameters go on the final line.
|
|
245
|
+
|
|
246
|
+
Good:
|
|
247
|
+
|
|
248
|
+
```console
|
|
249
|
+
$ pipx install \
|
|
250
|
+
--suffix=@next \
|
|
251
|
+
--pip-args '\--pre' \
|
|
252
|
+
--force \
|
|
253
|
+
'cihai-cli'
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Bad:
|
|
257
|
+
|
|
258
|
+
```console
|
|
259
|
+
$ pipx install --suffix=@next --pip-args '\--pre' --force 'cihai-cli'
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Changelog Conventions
|
|
263
|
+
|
|
264
|
+
These rules apply when authoring entries in `CHANGES`, which is rendered as the Sphinx changelog page. Modeled on Django's release-notes shape — deliverables get titles and prose, not bullets.
|
|
265
|
+
|
|
266
|
+
**Release entry boilerplate.** Every release header is `## cihai-cli X.Y.Z (YYYY-MM-DD)`. The file opens with a `## cihai-cli X.Y.Z (unreleased)` placeholder block fenced by `<!-- KEEP THIS PLACEHOLDER ... -->` and `<!-- END PLACEHOLDER ... -->` HTML comments — new release entries land immediately below the END marker, never above it.
|
|
267
|
+
|
|
268
|
+
**Open with a multi-sentence lead paragraph.** Plain prose, no italic. Open with the version as sentence subject (*"cihai-cli X.Y.Z ships …"*) so the lead is self-contained when excerpted. Two to four sentences telling the reader what shipped and who cares — user-visible takeaways, not internal mechanism. Cross-reference detail docs with `{ref}` to keep the lead compact.
|
|
269
|
+
|
|
270
|
+
**Each deliverable is a section, not a bullet.** Inside `### What's new`, every distinct deliverable gets a `#### Deliverable title (#NN)` heading naming it in user vocabulary, followed by 1-3 prose paragraphs explaining what shipped. Don't wrap a paragraph in `- ` — bullets are for enumerable lists, not paragraph containers. Cross-link detail docs (`See {ref}\`foo\` for details.`) so prose stays focused.
|
|
271
|
+
|
|
272
|
+
**The deliverable test.** Before writing an entry, ask: "What's the deliverable, in user vocabulary?" If you can't answer in one sentence, the entry isn't ready. Mechanism (helper internals, byte counters, schema-validation locations) belongs in PR descriptions and code comments, not the changelog.
|
|
273
|
+
|
|
274
|
+
**Fixed subheadings**, in this order when present: `### Breaking changes`, `### Dependencies`, `### What's new`, `### Fixes`, `### Documentation`, `### Development`. Dev tooling (helper scripts, internal automation) lives under `### Development`. For breaking changes, show the migration path with concrete inline code (e.g. a `# Before` / `# After` fenced code block). Dependency floor bumps use the form ``Minimum `pkg>=X.Y.Z` (was `>=X.Y.W`)``.
|
|
275
|
+
|
|
276
|
+
**PR refs `(#NN)`** sit in each deliverable's `####` heading.
|
|
277
|
+
|
|
278
|
+
**When bullets are appropriate.** Catch-all sections (`### Fixes`, occasionally `### Documentation`) with 3+ genuinely small items use bullets — one line each, never paragraphs. If a bullet swells past two lines, promote it to a `#### Title (#NN)` heading with prose body.
|
|
279
|
+
|
|
280
|
+
**Anti-patterns.**
|
|
281
|
+
|
|
282
|
+
- Fragile metrics: token ceilings, third-party version pins, percent benchmarks, exact byte counts. Describe the *capability*, not the math.
|
|
283
|
+
- Internal jargon: private symbols (leading-underscore identifiers), algorithm names exposed for the first time, backend scaffolding.
|
|
284
|
+
- Walls of text dressed up as bullets.
|
|
285
|
+
- Buried breaking changes — they get their own subheading at the top of the entry.
|
|
286
|
+
|
|
287
|
+
**Always link autodoc'd APIs.** Any class, method, function, exception, or attribute that has its own rendered page must be cited via the appropriate role (`{class}`, `{meth}`, `{func}`, `{exc}`, `{attr}`) — never with plain backticks. Doc pages without explicit ref labels use `{doc}`. Plain backticks are correct for code syntax, env vars, parameter names, and file paths that aren't doc pages — anything without an autodoc destination.
|
|
288
|
+
|
|
289
|
+
**MyST roles.** Class references use `{class}`, methods use `{meth}`, functions use `{func}`, exceptions use `{exc}`, attributes use `{attr}`, internal anchors use `{ref}`, doc-path links use `{doc}`.
|
|
290
|
+
|
|
291
|
+
**Summarization style.** When a user asks "what changed in the latest version?" or similar, lead with the entry's lead paragraph (paraphrased if needed), followed by each `####` deliverable heading under `### What's new` with a one-sentence summary. Cite `(#NN)` only if the user asks for source links. Don't invent versions, dates, or numbers not present in `CHANGES`. Don't quote line numbers or file offsets — those shift as the file evolves.
|
|
292
|
+
|
|
293
|
+
## Debugging Tips
|
|
294
|
+
- Lean on `pytest -k <pattern> -vv` for focused failures.
|
|
295
|
+
- For CLI behavior, run `uv run cihai info 好` or `uv run cihai reverse library`.
|
|
296
|
+
- If Unihan DB is missing, CLI bootstraps automatically; avoid altering that flow unless required.
|
|
297
|
+
- Stuck in loops? Pause, minimize to a minimal repro, document exact errors, and restate the hypothesis before another attempt.
|
|
298
|
+
|
|
299
|
+
## Git Commit Standards
|
|
300
|
+
|
|
301
|
+
Commit subjects: `Scope(type[detail]): concise description`
|
|
302
|
+
|
|
303
|
+
Body template:
|
|
304
|
+
```
|
|
305
|
+
why: Reason or impact.
|
|
306
|
+
|
|
307
|
+
what:
|
|
308
|
+
- Key technical changes
|
|
309
|
+
- Single topic only
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Guidelines:
|
|
313
|
+
- Subject ≤50 chars; body lines ≤72 chars; imperative mood.
|
|
314
|
+
- One topic per commit; separate subject and body with a blank line.
|
|
315
|
+
- Mark breaking changes with `BREAKING:` and include related issue refs when relevant.
|
|
316
|
+
|
|
317
|
+
Common commit types:
|
|
318
|
+
- **feat**: New features or enhancements
|
|
319
|
+
- **fix**: Bug fixes
|
|
320
|
+
- **refactor**: Code restructuring without functional change
|
|
321
|
+
- **docs**: Documentation updates
|
|
322
|
+
- **chore**: Maintenance (dependencies, tooling, config)
|
|
323
|
+
- **test**: Test-related updates
|
|
324
|
+
- **style**: Code style and formatting
|
|
325
|
+
- **py(deps)**: Dependencies
|
|
326
|
+
- **py(deps[dev])**: Dev dependencies
|
|
327
|
+
- **ai(rules[AGENTS])**: AI rule updates
|
|
328
|
+
- **ai(claude[rules])**: Claude Code rules (CLAUDE.md)
|
|
329
|
+
- **ai(claude[command])**: Claude Code command changes
|
|
330
|
+
|
|
331
|
+
#### Release commits
|
|
332
|
+
|
|
333
|
+
Never create tags. Never push tags. The user handles tagging and tag
|
|
334
|
+
pushes (tags trigger the CI publish workflow).
|
|
335
|
+
|
|
336
|
+
Release commit subjects are plain and short: `Tag v<version>`. Put
|
|
337
|
+
the detailed why/what in the commit body. Don't use the
|
|
338
|
+
`Scope(type[detail]):` format for releases — don't bury the lede.
|
|
339
|
+
|
|
340
|
+
## Notes & Docs Authoring
|
|
341
|
+
- For `notes/**/*.md`, keep content concise and well-structured (headings, bullets, code fences).
|
|
342
|
+
- Use clear link text `[Title](mdc:URL)` and avoid redundancy; follow llms.txt style when possible.
|
|
343
|
+
|
|
344
|
+
## References
|
|
345
|
+
- Project docs: https://cihai-cli.git-pull.com
|
|
346
|
+
- Library docs: https://cihai.git-pull.com
|
|
347
|
+
- Unihan dataset: https://www.unicode.org/charts/unihan.html
|
|
348
|
+
- Shared tooling: https://github.com/gp-libs/gp-libs
|
|
349
|
+
|
|
350
|
+
## AI Slop Prevention
|
|
351
|
+
|
|
352
|
+
Treat AI slop as **review-hostile noise**, not as proof that text or
|
|
353
|
+
code is wrong. The goal is to maximize information density by removing
|
|
354
|
+
artifacts that make the repository harder to trust or navigate.
|
|
355
|
+
|
|
356
|
+
### The Anti-Slop Rubric
|
|
357
|
+
|
|
358
|
+
Before committing, audit all AI-assisted changes for these noise
|
|
359
|
+
patterns:
|
|
360
|
+
|
|
361
|
+
- **AI Signatures:** Remove "Generated by", footers, conversational
|
|
362
|
+
filler ("Certainly!", "Here is..."), unexplained emojis (🤖, ✨), and
|
|
363
|
+
AI-tool metadata.
|
|
364
|
+
- **Brittle References:** Avoid hard-coded line numbers, fragile
|
|
365
|
+
file/test counts, dated "as of" claims, bare SHAs, and local
|
|
366
|
+
absolute paths unless they are strict evidentiary artifacts (e.g.,
|
|
367
|
+
benchmark logs).
|
|
368
|
+
- **Diff Narration:** Do not restate what moved, was renamed, or was
|
|
369
|
+
removed in artifacts the downstream reader holds: code, docstrings,
|
|
370
|
+
README, CHANGES, PR descriptions, or release notes. The diff and
|
|
371
|
+
commit message already carry this history.
|
|
372
|
+
- **Branch-Internal Narrative:** Do not mention intermediate branch
|
|
373
|
+
states, abandoned approaches, or "no longer" behavior unless users
|
|
374
|
+
of a published release actually experienced the old state (**The
|
|
375
|
+
Published-Release Test**).
|
|
376
|
+
- **Low-Value Scaffolding:** Remove ownerless TODOs (`TODO: revisit`),
|
|
377
|
+
unused future-proofing, debug artifacts, and defensive wrappers that
|
|
378
|
+
do not protect a currently reachable failure mode.
|
|
379
|
+
- **Prose Inflation:** Replace generic AI "tells" like *comprehensive,
|
|
380
|
+
robust, seamless, production-ready, leverage, delve, tapestry,* and
|
|
381
|
+
*best practices* with concrete descriptions of behavior,
|
|
382
|
+
constraints, or trade-offs.
|
|
383
|
+
|
|
384
|
+
### Preservation & Context
|
|
385
|
+
|
|
386
|
+
**When unsure, leave the text in place and ask.** Subjective cleanup
|
|
387
|
+
must never be a reason to remove load-bearing rationale.
|
|
388
|
+
|
|
389
|
+
- **Preserve the "Why":** You MUST NOT delete comments that document
|
|
390
|
+
invariants, protocol constraints, platform quirks, security
|
|
391
|
+
boundaries, and upstream workarounds.
|
|
392
|
+
- **Evidence is Immune:** Preserve exact counts, dates, and SHAs when
|
|
393
|
+
they serve as evidence in benchmark results, release notes, stack
|
|
394
|
+
traces, or lockfiles.
|
|
395
|
+
- **Behavior Over Inventory:** A useful description explains what
|
|
396
|
+
changed for the *system or user*; it does not provide an inventory
|
|
397
|
+
of files or functions the diff already shows.
|
|
398
|
+
|
|
399
|
+
### The Published-Release Test
|
|
400
|
+
|
|
401
|
+
Long-running branches accumulate tactical decisions — renames,
|
|
402
|
+
refactors, attempts-then-reverts. When deciding what counts as
|
|
403
|
+
branch-internal, use trunk or the parent branch as the baseline — not
|
|
404
|
+
intermediate states inside the current branch. Ask:
|
|
405
|
+
|
|
406
|
+
> Did users of the most recently published release ever experience
|
|
407
|
+
> this old name, old behavior, or bug?
|
|
408
|
+
|
|
409
|
+
If the answer is **no**, it is branch-internal narrative. Move it to
|
|
410
|
+
the commit message and describe only the final state in the artifact.
|
|
411
|
+
|
|
412
|
+
**Keep in shipped artifacts:**
|
|
413
|
+
- Deprecations and migration guides for symbols that actually shipped.
|
|
414
|
+
- `### Fixes` entries for bugs that affected users of a published
|
|
415
|
+
release.
|
|
416
|
+
- Comments explaining *why the current code looks this way*
|
|
417
|
+
(invariants, platform quirks) that make sense to a reader who never
|
|
418
|
+
saw the previous version.
|
|
419
|
+
|
|
420
|
+
### Cleanup in Hindsight
|
|
421
|
+
|
|
422
|
+
When applying these rules retroactively from inside a feature branch,
|
|
423
|
+
first establish scope by diffing against the parent branch (or trunk)
|
|
424
|
+
to identify which commits this branch actually introduced. Then:
|
|
425
|
+
|
|
426
|
+
- **In-branch commits:** Prompt the user with two options: `fixup!`
|
|
427
|
+
commits with `git rebase --autosquash` to address each causal commit
|
|
428
|
+
at its source, or a single cleanup commit at branch tip.
|
|
429
|
+
- **Trunk/Parent commits:** Default to leaving them alone. Act only on
|
|
430
|
+
explicit user instruction. If the user opts in, fold the cleanup
|
|
431
|
+
into a single commit at branch tip; do not rewrite shared history.
|
|
432
|
+
- **Scope guard:** If cleaning prior slop would touch a colleague's
|
|
433
|
+
work or expand the branch beyond its stated goal, stay in lane:
|
|
434
|
+
protect the current goal and leave prior slop alone.
|
|
435
|
+
|