Skip to content

v0.20.0

Choose a tag to compare

@mortenoh mortenoh released this 24 Apr 14:57
· 82 commits to main since this release
v0.20.0
c84f9c1

Highlights

chapkit migrate — convert an MLproject into a committable chapkit service (#39)

Point chapkit at an MLflow-style MLproject directory and get a first-class chapkit project you can edit, commit, extend, and ship as your own image. Code-generating sibling of chapkit run — where run adapts at runtime without touching files, migrate writes a proper project layout.

chapkit migrate              # current directory
chapkit migrate --dry-run    # print the plan, touch nothing
chapkit migrate --yes        # skip prompts (CI)

Generates at the project root: main.py, Dockerfile (pointing at the right chapkit-images base), pyproject.toml + requirements.txt with your original deps merged in, compose.yml, Makefile, postman_collection.json, CHAPKIT.md, plus .gitignore / .dockerignore. Original MLproject, stale data, and anything chapkit regenerates go to _old/ (recoverable — never deleted).

Key behaviours:

  • Dependency merge from three sources (user pyproject.toml, requirements.txt, MLproject python_env / conda_env — falling back to pyenv.yaml / conda.yaml / environment.yaml). sklearn -> scikit-learn rewrite. Conda-native scalars filtered out. PEP 508 markers with quotes, -r includes (recursive), -c constraints, --find-links, --extra-index-url, -e . all pass through; [tool.uv] gets index / find-links / constraint-dependencies for uv-first workflows.
  • user_options become typed BaseConfig fields. Non-identifier names (n-lags, class, 1st_period) normalized on the Python class and preserved on the wire via Pydantic Field(alias="...").
  • Base image auto-detection: chapkit-py / chapkit-r / chapkit-r-inla from source content + MLproject docker_env. Override with --base-image.
  • Interactive prompts for plan confirmation, ambiguous mixed-language base-image, unknown MLproject parameters; --yes suppresses for CI, --dry-run never prompts.
  • _old/ is never overwritten: hard error if it already exists. No --force, no timestamp rotation.

Validated end-to-end against six real chap-models repos (3/6 fully green out of the box; the remaining three migrate cleanly and services come up healthy — their failures are upstream model bugs with documented one-line patches).

ShellModelRunner.config_format — match chap-core's config.yml layout (#39)

New config_format: Literal["flat", "chap_core"] arg on ShellModelRunner. migrate-generated main.py opts into "chap_core" so config.yml matches chap-core's ModelConfiguration shape — reserved fields (prediction_periods, additional_continuous_covariates) stay top-level, everything else nests under user_option_values. Scripts ported from chap-models repos can read config["user_option_values"]["<option>"] (Python) or config$user_option_values$<option> (R) unchanged. chapkit init scaffolds keep the "flat" default — no behaviour change for existing users. chapkit run's runtime path picks up the same chap-core format.

Guards + fixes that also benefit chapkit run

  • runner.py's ValidationDiagnostic import is guarded behind TYPE_CHECKING, so volume-mounting current runner.py onto a container whose chapkit pre-dates that class no longer breaks module load.
  • chapkit run inherits the same sanitization: non-identifier user_options, dump_config_yaml via by_alias=True, canonical parameter mapping.
  • Startup prints a Docker one-liner hint to short-cut the typical "which image do I mount?" question.

Docs

  • chapkit migrate reference — flags, classification rules, generated files, base-image auto-detection, user_options -> Config, dry-run, interactive prompts.
  • MLproject migration checklist — before / during / after migration for shell-based runners, including the three failure shapes seen in the chap-models sweep.
  • Generated CHAPKIT.md in each migrated repo — TL;DR table, run-locally vs Docker, expanded chapkit test section, config.yml layout, covariates guidance.

Full changelog

  • feat(cli): add chapkit migrate for MLproject -> chapkit conversion (#39)
  • feat(runner,migrate): opt-in chap-core config.yml layout via config_format
  • feat(run,mlproject): carry the migrate fixes into chapkit run's runtime path
  • feat(run): print Docker one-liner hint on startup
  • feat(migrate): detect install_packages.R and bake its packages into the image
  • feat(migrate): warn about unpinned dependencies in the summary output
  • feat(migrate): fall back to conventional env files when MLproject is silent
  • feat(migrate): emit MLServiceInfo with model_metadata pulled from MLproject
  • feat(migrate): generate a Makefile with install/run/test/docker targets
  • feat(migrate): wire .with_registration() into generated main.py
  • feat(migrate,test): pyenv/conda dep merge, sklearn alias, chap-core-standard columns
  • feat(test): --predict-rows and new default for 2y+ context models
  • fix(runner): guard ValidationDiagnostic import behind TYPE_CHECKING
  • fix(migrate): guard against main.py collisions (chap-models/chap_pymc case)
  • fix(migrate): follow -r recursively, preserve index directives, warn on unknown
  • fix(migrate): rewrite nested -c constraint and --find-links paths relative to project root
  • fix(migrate): -c constraint files pass through verbatim, don't recurse as deps
  • fix(migrate): read deps from requirements.txt too; install via uv pip install -r, not inline shell args
  • fix(migrate): escape templated strings, filter conda-native deps, alias non-identifier option names
  • fix(migrate): follow pip's comment rules when parsing requirements.txt
  • fix(migrate): pin chapkit>=0.19.0 floor; USER root in Dockerfile
  • fix(migrate,init): image-level healthcheck; drop redundant compose declaration
  • chore: release v0.20.0

Full diff: v0.19.0...v0.20.0