Skip to content

Commit 1ff6179

Browse files
committed
wip: add AGENTS.md
Signed-off-by: Tomas Pereira de Vasconcelos <tomasvasconcelos1@gmail.com>
1 parent 72536c6 commit 1ff6179

5 files changed

Lines changed: 335 additions & 2 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY
2+
version = 1
3+
name = "ridgeplot"
4+
5+
[setup]
6+
script = '''
7+
if git remote | grep -q '^origin$'; then
8+
echo "info: git remote 'origin' already exists"
9+
else
10+
git remote add origin https://github.com/tpvasconcelos/ridgeplot.git
11+
fi
12+
if git rev-parse --is-shallow-repository 2>/dev/null | grep -q true; then
13+
git fetch --unshallow
14+
else
15+
echo "info: git repository is already complete (not shallow)"
16+
fi
17+
git fetch -v
18+
make init
19+
source .venv/bin/activate
20+
'''
21+
22+
[[actions]]
23+
name = "source venv"
24+
icon = "tool"
25+
command = "source .venv/bin/activate"
26+
27+
[[actions]]
28+
name = "tox -m tests"
29+
icon = "test"
30+
command = "tox -m tests"
31+
32+
[[actions]]
33+
name = "tox -m static-quick"
34+
icon = "test"
35+
command = "tox -m static-quick"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
description: Dropping and/or adding support for Python versions
3+
alwaysApply: false
4+
---
5+
This project tries to follow the [official](https://devguide.python.org/versions/) Python support policy.
6+
7+
When a new Python version is released, support for it should be added in the CI pipeline as soon as possible. This means updating `.github/workflows/ci.yml`'s `jobs.software-tests.strategy.matrix.python-version` and `pyproject.toml`'s `project.classifiers` to include the new version.
8+
9+
When a Python version reaches its end-of-life, support for it should be dropped. This means removing it from the CI pipeline and updating the following entries:
10+
11+
- `.github/workflows/ci.yml`:
12+
- `jobs.software-tests.strategy.matrix.python-version`
13+
- `jobs.static-checks.steps.with.python-version`
14+
- `.github/workflows/release.yml`:
15+
- `jobs.build.steps.with.python-version`
16+
- `jobs.github-release.steps.with.python-version`
17+
- `.pre-commit-config.yaml`: `default_language_version.python`
18+
- `.readthedocs.yml`: `build.tools.python`
19+
- `AGENTS.md`: Wherever relevant
20+
- `docs/development/contributing.md`: Wherever relevant
21+
- `makefile`: `BASE_PYTHON`
22+
- `mypy.ini`: `python_version`
23+
- `pyproject.toml`
24+
- `project.classifiers`
25+
- `project.requires-python`
26+
- `pyrightconfig.json`: `pythonVersion`
27+
- `ruff.toml`: `target-version`
28+
29+
In both instances, you should also update `docs/reference/changelog.md` to reflect the change in supported Python versions for the next release.
30+
31+
- When adding support for a new Python version, you can add an _"Add support for Python 3.XX, in accordance with the official Python support policy[^1] ({gh-pr}`XXX`)"_ entry at the top of the _"Unreleased changes"_ section.
32+
- When dropping support for a Python version, you can add a _"Dropped support for Python 3.XX, in accordance with the official Python support policy[^1] ({gh-pr}`XXX`)"_ entry in a _"Breaking changes"_ section under the _"Unreleased changes"_ section.

.cursor/worktrees.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"setup-worktree": [
3-
"make init"
3+
"make init",
4+
"source .venv/bin/activate"
45
]
56
}

AGENTS.md

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# ridgeplot Development Guide for AI Agents
2+
3+
`ridgeplot` is a Python package that provides a simple interface for plotting beautiful and interactive ridgeline plots within the extensive Plotly ecosystem.
4+
5+
This file provides guidance for AI assistants working with the ridgeplot codebase.
6+
7+
## Public API Overview
8+
9+
The library only exposes three public functions to end users.
10+
11+
Two of these functions are toy dataset loaders (`ridgeplot.datasets.load_probly()` and
12+
`ridgeplot.datasets.load_lincoln_weather()`) but they are not the focus on the project and are only exposed for backwards compatibility reasons.
13+
14+
The third function (`ridgeplot.ridgeplot()`) is a Plotly Figure (
15+
`plotly.graph_objects.Figure`) factory function, and it's the focus of this project. See its docstring at
16+
`src/ridgeplot/_ridgeplot.py` for full details.
17+
18+
## .cursor rules directory
19+
20+
You can check
21+
`.cursor/rules` before providing recommendations or generating code. This directory contains the authoritative rules for all development aspects.
22+
23+
To find the relevant rules:
24+
25+
1. Find ALL .md files in `.cursor/rules`
26+
2. Read ALL relevant rules files, based on the filetypes/languages/libraries/tasks/folders involved (e.g., .tsx, .css, .java, React,
27+
`//web/src/pages/home`, etc)
28+
3. If unsure, read metadata (first 5 lines) of any .mdc file to check rule scope/description/keywords
29+
30+
**For common tasks, you can check these specific files:**
31+
32+
- Bazel/testing: `.cursor/rules/bazel-test-execution.mdc`
33+
- Java code: `.cursor/rules/java-conventions.mdc`
34+
- TypeScript/web: `.cursor/rules/web-conventions.mdc`
35+
- Pull requests: `.cursor/rules/pull-request-conventions.mdc`
36+
37+
**Documentation:** https://ridgeplot.readthedocs.io/en/stable/
38+
39+
**Python Version**: Requires Python 3.10+
40+
41+
## Common Commands
42+
43+
### Environment Setup
44+
45+
```bash
46+
# Initialize full development environment (recommended for first-time setup)
47+
# This creates .venv, installs dependencies, and sets up pre-commit hooks
48+
make init
49+
50+
# Use a different Python version if needed (default is python3.10)
51+
BASE_PYTHON=python3.14 make init
52+
53+
# Offline mode (uses cached packages only) - useful when the internet is down
54+
OFFLINE=1 make init
55+
56+
# Activate the virtual environment
57+
source .venv/bin/activate
58+
```
59+
60+
### Running Tests
61+
62+
```bash
63+
# Run all test suits (unit + e2e + cicd_utils)
64+
tox -m tests
65+
66+
# Run a specific test suite
67+
tox -e tests-unit # Unit tests with coverage
68+
tox -e tests-e2e # End-to-end tests
69+
tox -e tests-cicd_utils # CI/CD utilities tests
70+
71+
# Run pytest directly with custom options
72+
tox -e pytest -- tests/unit/test_init.py --no-cov
73+
tox -e pytest -- -k "test_specific_function" --no-cov
74+
```
75+
76+
### Linting and Formatting
77+
78+
```bash
79+
# Run the main static checks
80+
tox -m static-quick
81+
82+
# Run the entire suite of static checks (incl. all pre-commit hooks)
83+
# If running from the main branch, you'll need
84+
# to skip the 'no-commit-to-branch' check with:
85+
SKIP='no-commit-to-branch' tox -m static
86+
87+
# Run specific pre-commit hooks
88+
pre-commit run ruff --all-files
89+
pre-commit run ruff-format --all-files
90+
91+
# Run type checking with pyright only
92+
tox -e typing
93+
```
94+
95+
### Documentation
96+
97+
```bash
98+
# Build static documentation
99+
tox -e docs-static
100+
```
101+
102+
## Architecture Overview
103+
104+
```
105+
src/ridgeplot/
106+
├── __init__.py # Public API exports
107+
├── _ridgeplot.py # Main ridgeplot() function
108+
├── _figure_factory.py # Plotly Figure construction
109+
├── _kde.py # Kernel Density Estimation
110+
├── _hist.py # Histogram binning
111+
├── _types.py # Type aliases and type guards
112+
├── _utils.py # Utility functions
113+
├── _missing.py # Sentinel for missing values
114+
├── _version.py # Version string (setuptools-scm)
115+
├── _color/ # Color handling
116+
│ ├── colorscale.py # Colorscale resolution
117+
│ ├── css_colors.py # CSS color parsing
118+
│ ├── interpolation.py # Color interpolation
119+
│ └── utils.py # Color utilities
120+
├── _obj/traces/ # Trace objects
121+
│ ├── area.py # Area trace (filled curves)
122+
│ ├── bar.py # Bar trace (histograms)
123+
│ └── base.py # Base trace class
124+
├── _vendor/ # Vendored dependencies
125+
└── datasets/ # Built-in datasets
126+
└── data/ # CSV data files
127+
128+
tests/
129+
├── conftest.py # Shared pytest fixtures
130+
├── unit/ # Unit tests for individual modules
131+
├── e2e/ # End-to-end tests with expected outputs
132+
│ └── artifacts/ # JSON artifacts for e2e comparisons
133+
└── cicd_utils/ # Tests for CI/CD utilities
134+
135+
cicd_utils/ # CI/CD helper modules
136+
├── cicd/ # Scripts and test helpers
137+
└── ridgeplot_examples/ # Example implementations for docs/testing
138+
```
139+
140+
### Key Data Flow
141+
142+
1. User calls `ridgeplot(samples=...)` or `ridgeplot(densities=...)`
143+
2. If samples provided → KDE (`_kde.py`) or histogram binning (`_hist.py`) produces densities
144+
3. Densities are normalised if `norm` parameter is set
145+
4. `create_ridgeplot()` in `_figure_factory.py` builds the Plotly Figure:
146+
- Resolves colorscale and computes colors for each trace
147+
- Creates trace objects (area or bar) for each density
148+
- Applies layout settings (spacing, padding, axes)
149+
5. Returns a `plotly.graph_objects.Figure` that users can further customise
150+
151+
### Type System
152+
153+
The codebase uses extensive type annotations. Key types in `_types.py`:
154+
155+
- **Samples/Densities**: Ragged 3D arrays `[rows][traces_per_row][values]`
156+
- **ShallowSamples/ShallowDensities**: 2D arrays (one trace per row)
157+
- **ColorScale**: `Collection[tuple[float, Color]]`
158+
- **Type guards**: `is_shallow_samples()`, `is_densities()`, etc.
159+
160+
## Code Style Guidelines
161+
162+
### General
163+
164+
- **Python version**: 3.10+ (uses modern typing features)
165+
- **Line length**: 100 characters
166+
- **Formatting**: Ruff (replaces black, isort, flake8)
167+
- **Imports**: Always include `from __future__ import annotations`
168+
- **Docstrings**: NumPy style
169+
- **Type annotations**: Use full and modern type annotations throughout with strict pyright checking
170+
171+
### Type Annotations
172+
173+
- All functions must be fully typed
174+
- Use `TYPE_CHECKING` blocks for import-only types
175+
- Uses **pyright** in strict mode (see `pyrightconfig.json`)
176+
- Use type guards for runtime type narrowing (see `_types.py`)
177+
- Follow this general principle for user-facing code: be contravariant in the input type and covariant in the output type
178+
179+
## Working with This Codebase
180+
181+
### When Adding New Features
182+
183+
1. Start with `_ridgeplot.py` to understand the main entry point
184+
2. Add new parameters following the existing patterns (with proper deprecation handling)
185+
3. Update type annotations in `_types.py` if introducing new data structures
186+
4. Add tests in `tests/unit/` with good coverage
187+
5. Update documentation in docstrings following the existing conventions
188+
189+
### When Fixing Bugs
190+
191+
1. Write a failing test first
192+
2. Fix the issue with minimal changes
193+
3. Ensure all existing tests pass
194+
4. Check type annotations are correct
195+
196+
### Common Patterns
197+
198+
**Handling deprecated parameters:**
199+
200+
```python
201+
if deprecated_param is not MISSING:
202+
if new_param is not None:
203+
raise ValueError("Cannot use both...")
204+
warnings.warn("...", DeprecationWarning, stacklevel=2)
205+
new_param = deprecated_param
206+
```
207+
208+
**Type narrowing with guards:**
209+
210+
```python
211+
if is_shallow_samples(samples):
212+
samples = nest_shallow_collection(samples)
213+
samples = cast("Samples", samples)
214+
```
215+
216+
**Lazy imports for performance:**
217+
218+
```python
219+
# Heavy imports inside functions to reduce import time
220+
def _coerce_to_densities(...):
221+
from ridgeplot._kde import estimate_densities # statsmodels is slow to import
222+
```
223+
224+
### Testing Tips
225+
226+
- Use `--no-cov` flag during development for faster test runs
227+
- Run specific tests: `tox -e pytest -- tests/unit/test_ridgeplot.py -k "test_name" --no-cov`
228+
- The `tests/e2e/artifacts/` directory contains expected Plotly Figure JSON for e2e tests
229+
- `conftest.py` patches `fig.show()` to prevent browser windows during tests
230+
231+
### Key Files to Know
232+
233+
| File | Purpose |
234+
|------------------------------------|-----------------------------|
235+
| `src/ridgeplot/_ridgeplot.py` | Main `ridgeplot()` function |
236+
| `src/ridgeplot/_figure_factory.py` | Figure construction logic |
237+
| `src/ridgeplot/_types.py` | All type aliases and guards |
238+
| `tests/unit/test_ridgeplot.py` | Core function tests |
239+
| `cicd_utils/ridgeplot_examples/` | Example scripts for docs |
240+
| `tox.ini` | CI environment definitions |
241+
| `ruff.toml` | Linting configuration |
242+
243+
## CI/CD Pipeline
244+
245+
Tests run on GitHub Actions across:
246+
247+
- Python versions: 3.10, 3.11, 3.12, 3.13, 3.14
248+
- Operating systems: Ubuntu, macOS, Windows
249+
250+
Coverage is uploaded to Codecov with:
251+
252+
- Overall: 98% minimum
253+
- Diff coverage: 100% for new code
254+
255+
## Notes for AI Assistants
256+
257+
1. **Always run tests** after making changes: `tox -e pytest -- <path> --no-cov`
258+
2. **Check types** with: `tox -e typing`
259+
3. **Format code** with: `pre-commit run ruff-format --all-files`
260+
4. **Respect existing patterns** - this is a mature codebase with consistent style
261+
5. **Don't add unnecessary abstractions** - keep changes minimal and focused
262+
6. **Preserve deprecation warnings** - the library maintains backward compatibility
263+
7. **Update docstrings** when changing function signatures
264+
8. **Use type guards** for runtime type narrowing instead of assertions

MANIFEST.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ prune docs/api/autogen
3333
prune docs/api/public
3434

3535
# Misc
36-
recursive-include .cursor *.json
36+
recursive-include .codex *.toml
37+
recursive-include .cursor *.json *.md
3738
recursive-include .github *.yml *.yaml
3839
recursive-include cicd_utils README.md *.py *.sh
3940
recursive-include misc *.py *.ipynb *.txt *.png

0 commit comments

Comments
 (0)