Skip to content

Commit fd70d45

Browse files
hmgaudeckerclaude
andauthored
Strong typing (#83)
* Refactor model configuration to use frozen dataclasses instead of dicts Introduce strongly-typed dataclasses for model configuration: - Dimensions, Labels, Anchoring, EstimationOptions, TransitionInfo - FactorEndogenousInfo, EndogenousFactorsInfo This improves type safety and enables IDE autocompletion while keeping user-facing model_dict as a plain dictionary. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Use frozendict for immutable dict fields in dataclasses Replace dict fields with frozendict in frozen dataclasses to ensure true immutability: - Labels.aug_periods_to_periods - Labels.aug_stages_to_stages - Anchoring.outcomes - TransitionInfo.param_names, individual_functions, function_names - EndogenousFactorsInfo.aug_periods_to_aug_period_meas_types, factor_info 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Ignore ty false positive. * Return ProcessedModel dataclass from process_model() instead of dict Update process_model() to return a ProcessedModel frozen dataclass and update all consumers to use attribute access instead of dict access. This provides: - Better type safety with explicit typed fields - Immutability via frozen dataclass - IDE autocomplete support - Clear documentation of the model structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Rename FactorEndogenousInfo to FactorInfo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Ensure complete typing in src/skillmodels. * Require Python 3.14 before fixing type annotations. * Move TESTS_DIR -> TEST_DATA_DIR, which points to a subdirectory of src so that config.TEST_DATA_DIR is valid also for skillmodels the package (as opposed to the project). * Fix more linting issues. * Make ruff rules much stricter. * Further tighten type annotations. Fix a missing run-time annotation of NDArray. * Move unsafe_fixes = false from .pre-commit config to pyproject. * Fix query in data simulation. * More fixes to imports, add test. * Use more tuples in place of lists to prevent errors. * Fix typing. * Dataclasses for user input. * Simplify. * Use modern rng everywhere. * Update CLAUDE.md * Get rid of if TYPE_CHECKING blocks * Update hooks and clean up * Call by name throughout. * Autogenerated docs, harmonised hooks / project configuration. * Get rid of model_dict. * Replace yaml model specifications by ModelSpec-s. * Next shot at fixing pickling. * Review comments 1: single EstimationOptions; improved dataclasses with all defaults set right there; get rid of remaining mutable types being passed around. * Review comments on docs; tighten typing of Mapping to MappingProxyType where we could do so. * Back to general implementation of ensure_containers_are_immutable. --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent dc87cf5 commit fd70d45

103 files changed

Lines changed: 7810 additions & 7291 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 36 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,52 @@
1-
# Byte-compiled / optimized / DLL files
2-
__pycache__/
3-
*.py[cod]
4-
*$py.class
5-
6-
# C extensions
7-
*.so
8-
91
# Distribution / packaging
10-
.Python
2+
*.egg
3+
*.egg-info/
4+
*.manifest
5+
*.spec
6+
.eggs/
7+
.installed.cfg
118
build/
12-
develop-eggs/
139
dist/
14-
downloads/
15-
eggs/
16-
.eggs/
17-
lib/
18-
lib64/
19-
parts/
10+
MANIFEST
2011
sdist/
21-
var/
2212
wheels/
23-
*.egg-info/
24-
.installed.cfg
25-
*.egg
26-
MANIFEST
27-
*build/
28-
29-
# PyInstaller
30-
# Usually these files are written by a python script from a template
31-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32-
*.manifest
33-
*.spec
34-
*.sublime-workspace
35-
*.sublime-project
3613

37-
# Installer logs
38-
pip-log.txt
39-
pip-delete-this-directory.txt
40-
41-
# Unit test / coverage reports
42-
htmlcov/
43-
.tox/
44-
.coverage
45-
.coverage.*
46-
.cache
47-
nosetests.xml
48-
coverage.xml
49-
*.cover
50-
.hypothesis/
51-
.pytest_cache/
52-
53-
# Translations
54-
*.mo
55-
*.pot
56-
57-
# Django stuff:
58-
*.log
59-
local_settings.py
60-
db.sqlite3
61-
62-
# Flask stuff:
63-
instance/
64-
.webassets-cache
65-
66-
# Scrapy stuff:
67-
.scrapy
68-
69-
# Sphinx documentation
14+
# Documentation
7015
docs/_build/
16+
_build/
7117

72-
# PyBuilder
73-
target/
74-
75-
# Jupyter Notebook
76-
.ipynb_checkpoints
77-
78-
# pyenv
79-
.python-version
80-
81-
# celery beat schedule file
82-
celerybeat-schedule
83-
84-
# SageMath parsed files
85-
*.sage.py
86-
87-
# Environments
88-
.env
89-
.venv
90-
env/
91-
venv/
92-
ENV/
93-
env.bak/
94-
venv.bak/
95-
96-
# Spyder project settings
97-
.spyderproject
98-
.spyproject
99-
100-
# Rope project settings
101-
.ropeproject
102-
103-
# mkdocs documentation
104-
/site
18+
# IDE
19+
.idea/
20+
.vscode/
10521

106-
# mypy
107-
.mypy_cache/
22+
# Jupyter
23+
.ipynb_checkpoints/
10824

109-
*notes/
25+
# macOS
26+
.DS_Store
11027

111-
.idea/
28+
# pixi
29+
.pixi/
11230

113-
*.bak
31+
# Python
32+
__pycache__/
33+
*.py[cod]
34+
*.so
35+
*$py.class
11436

37+
# Ruff
38+
.ruff_cache/
11539

116-
*.db
40+
# Testing
41+
.cache/
42+
.coverage
43+
.coverage.*
44+
.hypothesis/
45+
.pytest_cache/
46+
coverage.xml
47+
htmlcov/
11748

49+
# Version file (generated by hatch-vcs)
50+
src/*/_version.py
11851

119-
mixed_documents/
120-
src/skillmodels/_version.py
121-
.pixi
122-
.vscode
123-
*.py.*.bin
124-
*.py.*.html
52+
.claude

.pre-commit-config.yaml

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ repos:
44
hooks:
55
- id: check-hooks-apply
66
- id: check-useless-excludes
7-
# - id: identity # Prints all files passed to pre-commits. Debugging.
7+
- repo: https://github.com/tox-dev/tox-toml-fmt
8+
rev: v1.2.2
9+
hooks:
10+
- id: tox-toml-fmt
811
- repo: https://github.com/lyz-code/yamlfix
912
rev: 1.19.1
1013
hooks:
@@ -15,53 +18,51 @@ repos:
1518
- id: check-added-large-files
1619
args:
1720
- --maxkb=50000
21+
- id: check-ast
1822
- id: check-case-conflict
23+
- id: check-docstring-first
1924
- id: check-merge-conflict
25+
- id: check-toml
2026
- id: check-vcs-permalinks
2127
- id: check-yaml
22-
- id: check-toml
2328
- id: debug-statements
2429
- id: end-of-file-fixer
2530
- id: fix-byte-order-marker
2631
types:
2732
- text
28-
- id: forbid-submodules
2933
- id: mixed-line-ending
3034
args:
3135
- --fix=lf
3236
description: Forces to replace line ending by the UNIX 'lf' character.
37+
- id: name-tests-test
38+
args:
39+
- --pytest-test-first
3340
- id: no-commit-to-branch
3441
args:
3542
- --branch
3643
- main
37-
- id: name-tests-test
38-
args:
39-
- --pytest-test-first
4044
- id: trailing-whitespace
41-
- id: check-ast
42-
- id: check-docstring-first
4345
- repo: https://github.com/adrienverge/yamllint.git
44-
rev: v1.37.1
46+
rev: v1.38.0
4547
hooks:
4648
- id: yamllint
4749
- repo: https://github.com/astral-sh/ruff-pre-commit
48-
rev: v0.14.10
50+
rev: v0.14.14
4951
hooks:
5052
- id: ruff-check
51-
types_or:
52-
- python
53-
- pyi
54-
- jupyter
5553
args:
5654
- --fix
57-
# - --unsafe-fixes
58-
- id: ruff-format
5955
types_or:
60-
- python
56+
- jupyter
6157
- pyi
58+
- python
59+
- id: ruff-format
60+
types_or:
6261
- jupyter
62+
- pyi
63+
- python
6364
- repo: https://github.com/kynan/nbstripout
64-
rev: 0.8.2
65+
rev: 0.9.0
6566
hooks:
6667
- id: nbstripout
6768
args:
@@ -72,10 +73,12 @@ repos:
7273
hooks:
7374
- id: mdformat
7475
additional_dependencies:
75-
- mdformat-myst
76+
- mdformat-gfm
77+
- mdformat-gfm-alerts
7678
- mdformat-ruff
7779
args:
7880
- --wrap
7981
- '88'
82+
files: (CLAUDE\.md|README\.md)
8083
ci:
8184
autoupdate_schedule: monthly

.readthedocs.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
version: 2
3+
build:
4+
os: ubuntu-24.04
5+
tools:
6+
python: '3.14'
7+
nodejs: '22'
8+
jobs:
9+
create_environment:
10+
- asdf plugin add pixi
11+
- asdf install pixi latest
12+
- asdf global pixi latest
13+
install:
14+
- pixi install -e docs
15+
post_build:
16+
# Jupyter Book 2.0 builds site content to _build/html.
17+
# For ReadTheDocs, we build and then copy to the expected output location.
18+
- mkdir --parents $READTHEDOCS_OUTPUT/html/
19+
- BASE_URL="/$READTHEDOCS_LANGUAGE/$READTHEDOCS_VERSION" pixi run -e docs docs
20+
- cp -a docs/_build/html/. "$READTHEDOCS_OUTPUT/html" && rm -r docs/_build

.yamllint.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
---
2-
yaml-files:
3-
- '*.yaml'
4-
- '*.yml'
5-
- .yamllint
62
rules:
73
braces: enable
84
brackets: enable
@@ -23,14 +19,21 @@ rules:
2319
key-duplicates: enable
2420
key-ordering: disable
2521
line-length:
26-
max: 88
22+
allow-non-breakable-inline-mappings: true
2723
allow-non-breakable-words: true
28-
allow-non-breakable-inline-mappings: false
24+
max: 88
2925
new-line-at-end-of-file: enable
3026
new-lines:
3127
type: unix
3228
octal-values: disable
3329
quoted-strings: disable
3430
trailing-spaces: enable
3531
truthy:
32+
check-keys: false
3633
level: warning
34+
yaml-files:
35+
- '*.yaml'
36+
- '*.yml'
37+
- .yamllint
38+
ignore:
39+
- src/skillmodels/test_data/simplest_augmented_model.yaml

CLAUDE.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,29 @@ pixi run -e test-cpu pytest tests/test_kalman_filters.py::test_function_name
2727
# Type checking
2828
pixi run ty
2929

30-
# Install pre-commit hooks (required before committing)
31-
pre-commit install
30+
# Quality checks (linting, formatting)
31+
prek run --all-files
3232

3333
# Build documentation (from docs/ directory)
3434
make html
3535
```
3636

37+
## Command Rules
38+
39+
Always use these command mappings:
40+
41+
- **Python**: Use `pixi run python` instead of `python` or `python3`
42+
- **Type checker**: Use `pixi run ty` instead of running ty/mypy/pyright directly
43+
- **Tests**: Use `pixi run tests` instead of `pytest` directly
44+
- **Linting/formatting**: Use `prek run --all-files` instead of `ruff` directly
45+
- **All quality checks**: Use `prek run --all-files`
46+
47+
Before finishing any task that modifies code, always run:
48+
49+
1. `pixi run ty` (type checker)
50+
1. `pixi run tests` (tests)
51+
1. `prek run --all-files` (quality checks)
52+
3753
## Architecture
3854

3955
### Core Pipeline Flow
@@ -82,14 +98,19 @@ The main package exports three functions:
8298

8399
- `get_maximization_inputs()`: Prepare optimization problem for parameter estimation
84100
- `get_filtered_states()`: Extract filtered latent factor estimates
85-
- `simulate_dataset()`: Generate synthetic data from model specification
101+
- `simulate_dataset()`: Generate synthetic data from model specification (accepts
102+
optional `seed` parameter for reproducibility)
86103

87104
## Code Style
88105

89-
- Uses Ruff for linting (target: Python 3.13, line length: 88)
106+
- Require Python 3.14
107+
- Uses Ruff for linting (target: Python 3.14, line length: 88)
90108
- Google-style docstrings
91109
- Pre-commit hooks enforce formatting and linting
92110
- Type checking via `ty` with strict rules
111+
- Do not use `from __future__ import annotations`
112+
- Use modern numpy random API: `rng = np.random.default_rng(seed)` instead of
113+
`np.random.seed()` or legacy functions like `np.random.randn()`
93114

94115
## Testing
95116

0 commit comments

Comments
 (0)