Skip to content

Commit 71ce45c

Browse files
docs: Add CLAUDE.md
1 parent 5fa229d commit 71ce45c

File tree

1 file changed

+291
-0
lines changed

1 file changed

+291
-0
lines changed

CLAUDE.md

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code when working with code in this repository.
4+
5+
## Overview
6+
7+
**msgspec-ext** is a high-performance settings management library built on top of msgspec. It provides a pydantic-like API for loading settings from environment variables and .env files, with **3.8x better performance** than pydantic-settings.
8+
9+
## Project Structure
10+
11+
```
12+
msgspec-ext/
13+
├── src/msgspec_ext/ # Source code
14+
│ ├── settings.py # Core BaseSettings implementation
15+
│ └── version.py # Version string
16+
├── tests/ # Test suite
17+
│ └── test_settings.py # Comprehensive unit tests (22 tests)
18+
├── examples/ # Practical examples
19+
│ ├── 01_basic_usage.py
20+
│ ├── 02_env_prefix.py
21+
│ ├── 03_dotenv_file.py
22+
│ ├── 04_advanced_types.py
23+
│ ├── 05_serialization.py
24+
│ └── README.md
25+
├── scripts/ # Automation scripts
26+
│ ├── release.sh # Release automation (use this!)
27+
│ └── setup-branch-protection.sh
28+
└── benchmark.py # Performance benchmarks
29+
30+
## Common Commands
31+
32+
### Development
33+
34+
```bash
35+
# Install dependencies
36+
uv sync
37+
38+
# Install with dev dependencies
39+
uv sync --group dev
40+
41+
# Add new dependency
42+
uv add <package>
43+
44+
# Run tests
45+
uv run pytest tests/ -v
46+
47+
# Run specific test
48+
uv run pytest tests/test_settings.py::test_name -v
49+
50+
# Run linter (only checks src/)
51+
uv run ruff check src/
52+
53+
# Format code
54+
uv run ruff format
55+
56+
# Run benchmark
57+
uv run python benchmark.py
58+
```
59+
60+
### Testing
61+
62+
All tests are in `tests/test_settings.py`:
63+
- 22 comprehensive unit tests
64+
- Tests cover: basic usage, env vars, type conversion, .env files, validation, serialization
65+
- Run with: `uv run pytest tests/ -v`
66+
- Should complete in < 0.1s
67+
68+
### Releases
69+
70+
**IMPORTANT**: Always use the release script:
71+
72+
```bash
73+
# Create a new release
74+
./scripts/release.sh <version>
75+
76+
# Example:
77+
./scripts/release.sh 0.2.0
78+
```
79+
80+
The script will:
81+
1. Update `src/msgspec_ext/version.py`
82+
2. Create git tag
83+
3. Push to upstream
84+
4. Trigger GitHub Actions for PyPI publishing
85+
86+
**Never manually edit version.py** - always use the release script!
87+
88+
## Architecture
89+
90+
### Core Implementation (`settings.py`)
91+
92+
**Key optimization**: Uses bulk JSON decoding instead of field-by-field validation.
93+
94+
```python
95+
# Old approach (slow):
96+
for field in fields:
97+
value = msgspec.convert(env_value, field_type) # Python loop
98+
99+
# New approach (fast):
100+
json_bytes = encoder.encode(all_values) # Cached encoder
101+
return decoder.decode(json_bytes) # Cached decoder, all in C!
102+
```
103+
104+
**Important classes**:
105+
- `BaseSettings`: Wrapper factory that creates msgspec.Struct instances
106+
- `SettingsConfigDict`: Configuration (env_file, env_prefix, etc.)
107+
108+
**Performance optimizations**:
109+
- Cached encoders/decoders (ClassVar)
110+
- Automatic field ordering (required before optional)
111+
- Bulk JSON decoding in C
112+
- Zero Python loops for validation
113+
114+
### Type Handling
115+
116+
Environment variables are always strings, but we need proper types:
117+
118+
```python
119+
_preprocess_env_value(env_value: str, field_type: type) -> Any
120+
```
121+
122+
Handles:
123+
- `bool`: "true"/"false"/"1"/"0" → True/False
124+
- `int`/`float`: String to number conversion
125+
- `list`/`dict`: JSON parsing for complex types
126+
- `Optional[T]`: Unwraps Union types correctly
127+
128+
### Field Ordering
129+
130+
`msgspec.defstruct` requires required fields before optional fields. We handle this automatically in `_create_struct_class()`:
131+
132+
```python
133+
required_fields = [(name, type), ...]
134+
optional_fields = [(name, type, default), ...]
135+
fields = required_fields + optional_fields # Correct order
136+
```
137+
138+
## Linting & Code Style
139+
140+
**Ruff configuration** (`pyproject.toml`):
141+
- Target: Python 3.10+
142+
- Line length: 88
143+
- Strict linting for `src/`
144+
- Relaxed rules for `tests/` and `examples/`
145+
146+
**Running lint**:
147+
```bash
148+
# Check only src/ (recommended for quick checks)
149+
uv run ruff check src/
150+
151+
# Check everything
152+
uv run ruff check
153+
154+
# Auto-fix issues
155+
uv run ruff check --fix
156+
157+
# Format code
158+
uv run ruff format
159+
```
160+
161+
**Important per-file ignores**:
162+
- `tests/`: Ignores D (docstrings), S104 (binding), S105 (passwords), etc.
163+
- `examples/`: Ignores D, S101, S104, S105, T201, F401
164+
- `benchmark.py`: Ignores D, S101, S105, T201, etc.
165+
166+
## Examples
167+
168+
5 practical examples in `examples/`:
169+
1. **Basic usage**: Defaults, env vars, explicit values
170+
2. **Environment prefixes**: Organizing settings with `env_prefix`
171+
3. **.env files**: Loading from dotenv files
172+
4. **Advanced types**: Optional, lists, dicts, JSON parsing
173+
5. **Serialization**: `model_dump()`, `model_dump_json()`, `schema()`
174+
175+
Run examples:
176+
```bash
177+
uv run python examples/01_basic_usage.py
178+
```
179+
180+
## Benchmarking
181+
182+
```bash
183+
uv run python benchmark.py
184+
```
185+
186+
Expected results:
187+
- msgspec-ext: ~0.7ms per load
188+
- pydantic-settings: ~2.7ms per load (if installed)
189+
- **Speedup**: 3.8x faster than pydantic-settings
190+
191+
## CI/CD
192+
193+
GitHub Actions workflows:
194+
- **CI**: Runs on every push (Ruff, Tests, Build)
195+
- **Publish**: Publishes to PyPI on new tags
196+
- **Release Drafter**: Auto-generates release notes
197+
198+
**Creating a PR**:
199+
1. Create feature branch from main
200+
2. Make changes
201+
3. Run tests: `uv run pytest tests/ -v`
202+
4. Run lint: `uv run ruff check src/`
203+
5. Format: `uv run ruff format`
204+
6. Push and create PR
205+
7. Ensure CI passes (Ruff, Tests, Build)
206+
207+
## Common Workflows
208+
209+
### Adding a new feature
210+
211+
1. Create branch: `git checkout -b feat/feature-name`
212+
2. Implement feature in `src/msgspec_ext/settings.py`
213+
3. Add tests in `tests/test_settings.py`
214+
4. Add example in `examples/` (if user-facing)
215+
5. Run tests: `uv run pytest tests/ -v`
216+
6. Run lint: `uv run ruff check src/`
217+
7. Create PR
218+
219+
### Fixing a bug
220+
221+
1. Add failing test in `tests/test_settings.py`
222+
2. Fix bug in `src/msgspec_ext/settings.py`
223+
3. Verify test passes
224+
4. Run full test suite
225+
5. Create PR
226+
227+
### Updating dependencies
228+
229+
```bash
230+
# Update specific package
231+
uv add package@latest
232+
233+
# Update all dependencies
234+
uv sync --upgrade
235+
```
236+
237+
## Performance Tips
238+
239+
- **Always use cached encoder/decoder**: Don't create new instances
240+
- **Bulk operations**: Process all fields at once via JSON decode
241+
- **Avoid Python loops**: Let msgspec handle validation in C
242+
- **Field ordering**: Required before optional (automatic)
243+
- **Type hints**: Proper annotations enable better performance
244+
245+
## Troubleshooting
246+
247+
**Tests failing**:
248+
```bash
249+
uv run pytest tests/ -v # See detailed output
250+
```
251+
252+
**Lint errors**:
253+
```bash
254+
uv run ruff check src/ # Check src only
255+
uv run ruff check --fix # Auto-fix
256+
```
257+
258+
**Import errors**:
259+
```bash
260+
uv sync # Reinstall dependencies
261+
```
262+
263+
**Performance regression**:
264+
```bash
265+
uv run python benchmark.py # Compare with baseline
266+
```
267+
268+
## Key Files
269+
270+
- `src/msgspec_ext/settings.py` - Core implementation (most important)
271+
- `src/msgspec_ext/version.py` - Version (updated by release script)
272+
- `tests/test_settings.py` - Test suite (22 tests)
273+
- `benchmark.py` - Performance benchmarks
274+
- `scripts/release.sh` - Release automation (**use this for releases!**)
275+
- `pyproject.toml` - Project config, dependencies, ruff settings
276+
277+
## Documentation
278+
279+
- `README.md` - User-facing docs with quickstart
280+
- `examples/README.md` - Example gallery guide
281+
- `CONTRIBUTING.md` - Contribution guidelines
282+
- `CLAUDE.md` - This file (for Claude Code)
283+
284+
## Notes for Claude Code
285+
286+
- **Releases**: Always use `./scripts/release.sh <version>`, never edit version.py manually
287+
- **Linting**: Focus on `src/` only (`uv run ruff check src/`)
288+
- **Tests**: Must maintain 100% pass rate (22/22)
289+
- **Performance**: Benchmark should show ~0.7ms per load, 3.8x vs pydantic
290+
- **Examples**: Update if changing user-facing APIs
291+
- **Breaking changes**: Require major version bump

0 commit comments

Comments
 (0)