← Back to blog
2026-04-22

Session 1: Phase 0 (Groundwork) + most of Phase 1 (Amputation)

Engineering log for session 1.

Baseline: PyCaret 3.4.0 @ main. Environment: Python 3.13.13, uv 0.11.7, scikit-learn 1.7.2, NumPy 2.3.5, pandas 2.x on Windows.

BUILD#

  • BUILD, BREAKINGVersion bumped 3.4.04.0.0.dev0. pycaret/__init__.py and pyproject.toml now declare 4.0.0.dev0; this is a pre-release marker for the in-flight revamp.
  • BUILD, BREAKINGMigrated build backend from setuptools to hatchling. [build-system] in pyproject.toml now uses hatchling>=1.25. Wheel packaging handled by [tool.hatch.build.targets.wheel].
  • BUILD, BREAKINGMigrated environment management to uv (Astral). uv.lock becomes the lockfile; uv sync --all-extras is the supported one-command install. Dev dependencies live in [dependency-groups.dev].
  • BUILD, BREAKINGDeleted setup.cfg. pytest, flake8, and isort configs moved. Pytest config now lives in [tool.pytest.ini_options] in pyproject.toml. Flake8 / isort replaced by ruff (see below).
  • BUILD, BREAKINGDeleted MANIFEST.in. Hatchling's built-in include/exclude rules replace it.
  • BUILDDeleted mypy.ini. mypy config now lives in pyproject.toml's tool sections (reinstate there if/when mypy is run).
  • BUILD, BREAKINGPython floor raised from >=3.9,<3.13 to >=3.11. Classifiers now list 3.11 / 3.12 / 3.13 / 3.14. Primary dev target is Python 3.13 for session 1; 3.14 is aspirational (PEP 649 currently breaks joblib+cloudpickle pickling — see thinking/2026-04-22_python314_pep649_blocker.md).
  • BUILDRuff added as the single linter. Replaces the 3.x stack of black + isort + flake8. Config in [tool.ruff] / [tool.ruff.lint]. Target version py313.
  • BUILDHard-coded Python version guard rewritten. pycaret/__init__.py now raises RuntimeError if run under <3.11 instead of <3.9 or >=3.13.

DEPS — removed from runtime (kill list)#

All removals are pre-approved in KILL_LIST.md. Each is a BREAKING change against any user who relied on the affected feature.

  • REMOVED, BREAKINGmlflow. No longer a dependency; loggers/mlflow_logger.py module deleted.
  • REMOVED, BREAKINGcomet-ml. loggers/comet_logger.py deleted.
  • REMOVED, BREAKINGwandb. loggers/wandb_logger.py deleted.
  • REMOVED, BREAKINGdagshub. loggers/dagshub_logger.py deleted.
  • REMOVED, BREAKINGDashboardLogger fan-out logger. loggers/dashboard_logger.py deleted.
  • REMOVED, BREAKINGfugue, fugue[dask]. pycaret/parallel/fugue_backend.py deleted.
  • REMOVED, BREAKINGdask, distributed. No replacement.
  • REMOVED, BREAKINGray[tune], tune-sklearn. Ray Tune integration dropped from the tuners extra. optuna, scikit-optimize, and hyperopt remain.
  • REMOVED, BREAKINGyellowbrick. Plot layer deleted wholesale. pycaret/internal/plots/yellowbrick.py deleted; pycaret/internal/patches/yellowbrick.py deleted. 16 inline from yellowbrick.* import ... call sites in internal/pycaret_experiment/tabular_experiment.py stubbed behind a show_yellowbrick_plot NotImplementedError placeholder (see tabular_experiment.py transitional stubs). Replacements land in Phase 3 as native Plotly plots.
  • REMOVED, BREAKINGmljar-scikit-plot. scikitplot import removed from internal/plots/helper.py. The only functional dependency was a matplotlib re-export, which is now direct.
  • REMOVED, BREAKINGschemdraw. Pipeline diagram drawing (one code path) no longer supported; Phase 3 will decide whether to re-render it as Plotly.
  • REMOVED, BREAKINGplotly-resampler. display_format='plotly-widget' and display_format='plotly-dash' paths in time_series/forecasting/oop.py raise NotImplementedError. Plain Plotly rendering still works.
  • REMOVED, BREAKINGevidently. check_drift method (and its test) removed from all experiment classes.
  • REMOVED, BREAKINGfairlearn. check_fairness method (and its test) removed.
  • REMOVED, BREAKINGydata-profiling. eda method scheduled for removal; extras entry deleted.
  • REMOVED, BREAKINGexplainerdashboard. dashboard method scheduled for removal; extras entry deleted.
  • REMOVED, BREAKINGgradio. create_app method scheduled for removal; extras entry deleted.
  • REMOVED, BREAKINGfastapi, uvicorn. create_api method scheduled for removal; extras entry deleted. If a web server layer comes back it will be a separate pycaret-server package.
  • REMOVED, BREAKINGboto3. deploy_model's S3 path no longer supported. test_persistence.py S3 fixtures/tests removed.
  • REMOVED, BREAKINGm2cgen. convert_model method scheduled for removal; extras entry deleted.
  • REMOVED, BREAKINGmoto. Test-only dep for boto3 S3 mocking; removed.
  • REMOVED, BREAKINGflask, Werkzeug. parallel extras artifacts; removed with dask removal.
  • REMOVED, BREAKINGdash[testing]. explainerdashboard test dep; removed.
  • REMOVED, BREAKINGscikit-learn-intelex. Intel oneAPI sklearn-plus-daal4py extension dropped. engine="sklearnex" paths in the model containers will fail to match; corresponding tests were deleted.
  • REMOVED, BREAKINGtrio<0.25. Legacy httpcore workaround removed.
  • REMOVED, BREAKINGstatsforecast. Demoted from the timeseries extra. (Needed a C toolchain on Python 3.14 with no wheel; no PyCaret code imports it directly. Users can install manually.)
  • REMOVED, BREAKINGtbats. Demoted from the timeseries extra. (Declares numpy<2, incompatible with NumPy 2.x modernization. BATSContainer / TBATSContainer now try-import and silently mark themselves inactive if the package is missing; users can still pip install tbats manually.)

DEPS — upper-bound pins removed (modernization)#

All of these caps blocked PyCaret from running on modern Python or modern scientific-stack versions.

  • CHANGED, BREAKINGscikit-learn cap lifted from <1.5 to >=1.7,<1.8. The <1.8 upper bound is transitional: sktime (the timeseries extra) caps sklearn at <1.8. When sktime releases with sklearn 1.8 support, we bump.
  • CHANGED, BREAKINGnumpy cap lifted from <1.27 to no upper bound. Floor is >=1.26 (for NumPy 2.x API). Codebase updated to NumPy 2 compatibility; see fixes below.
  • CHANGED, BREAKINGpandas cap lifted from <2.2 to no upper bound. Floor is >=2.2.
  • CHANGED, BREAKINGscipy cap lifted from <=1.11.4 to no upper bound. Floor is >=1.11.
  • CHANGEDjoblib cap lifted from <1.5 to no upper bound. Floor is >=1.4.
  • REMOVEDmatplotlib upper bound <3.8.0 removed. matplotlib now declared >=3.9 as a transitional core dep (only used by residual non-Plotly plot paths — Phase 3 will remove it entirely).
  • REMOVEDsktime pinned release >=0.31.0,<0.31.1 unpinned to >=0.36.
  • REMOVEDshap upper bound <0.47.0 removed. Now >=0.46.
  • REMOVEDfairlearn==0.7.0 pin removed (fairlearn itself dropped).
  • REMOVEDevidently<0.4.30 pin removed (evidently dropped).
  • REMOVEDpmdarima exact version constraints relaxed. Floor >=2.0.4.
  • REMOVEDdask<2024.6.3, distributed<2024.6.3, fugue==0.9.1 pins removed (packages dropped).
  • REMOVEDWerkzeug>=2.2,<3.0 pin removed (dropped).
  • REMOVEDmoto<5.0.0 pin removed (dropped).

DEPS — optional-extras restructuring#

Extras reorganized from the 3.x layout (full, analysis, models, tuners, mlops, parallel, prophet, dev, test) to a cleaner 4.0 layout:

  • CHANGED, BREAKINGmlops extra deleted. Its contents (mlflow, gradio, fastapi, uvicorn, m2cgen, boto3, evidently) are on the kill list.
  • CHANGED, BREAKINGparallel extra deleted (dask/distributed/fugue gone).
  • ADDEDanomaly extra. Isolates pyod + numba so classification/regression users don't pay the install cost.
  • ADDEDtimeseries extra. Contains statsmodels, sktime, pmdarima; isolated from core because sktime's dep closure is heavy.
  • CHANGEDfull extra now means pycaret[models,tuners,analysis,anomaly,timeseries] (plain alias — no duplicated list).
  • CHANGEDtest extra gains pytest-xdist, pytest-cov, nbval; loses fugue[dask], dash[testing], moto.
  • CHANGEDdev dependency group replaces dev extra. Contents: ruff, mypy, pre-commit. (black/isort/flake8 dropped in favour of ruff.)
  • BUILDkaleido pinned to >=0.2 (core dep for Plotly static image export).
  • BUILDCore deps trimmed from 30 to 19. Removed from core: deprecation, markupsafe (Colab workaround), wurlitzer, importlib_metadata (stdlib now), setuptools (runtime), mljar-scikit-plot, schemdraw, plotly-resampler, yellowbrick, trio, plus the timeseries packages which moved to their extra.

REMOVED — modules and tests#

  • REMOVED, BREAKINGpycaret/parallel/ directory deleted.
  • REMOVED, BREAKINGpycaret/internal/parallel/ directory deleted.
  • REMOVED, BREAKINGpycaret/loggers/{mlflow,comet,wandb,dagshub,dashboard}_logger.py — five logger modules deleted.
  • REMOVED, BREAKINGpycaret/internal/patches/yellowbrick.py deleted.
  • REMOVED, BREAKINGpycaret/internal/plots/yellowbrick.py deleted.
  • TESTS14 test files deleted:
    • test_classification_parallel.py, test_regression_parallel.py, test_time_series_parallel.py (parallel gone)
    • test_mlflow_artifacts.py (was empty)
    • test_time_series_mlflow.py
    • test_create_api.py, test_create_app.py, test_create_docker.py
    • test_dashboard.py
    • test_check_drift.py, test_check_fairness.py
    • test_clustering_engines.py (daal4py-only)
    • test_classification_engines.py, test_regression_engines.py, test_time_series_engines.py (sklearnex-only)
  • TESTStest_persistence.py reduced to a single-line stub comment (all its tests were boto3/moto/S3 specific).

CHANGED — API / signature changes#

  • CHANGED, BREAKINGcompare_models(parallel=...) argument removed from 7 files: classification/{functional,oop}.py, regression/{functional,oop}.py, time_series/forecasting/{functional,oop}.py, internal/pycaret_experiment/supervised_experiment.py. Passing parallel= to compare_models will now raise TypeError: unexpected keyword argument.
  • REMOVED, BREAKING_parallel_compare_models method deleted from internal/pycaret_experiment/supervised_experiment.py.
  • CHANGED, BREAKINGsetup(log_experiment=...) no longer accepts string shortcuts ("mlflow", "comet_ml", "wandb", "dagshub"). Only bool or BaseLogger instances are valid now. _validate_log_experiment / _convert_log_experiment rewritten in internal/pycaret_experiment/tabular_experiment.py. The list[...] form is preserved but validates each element to the new rule.
  • CHANGED_convert_log_experiment now always returns a BaseLogger instance, never a bool. Downstream hooks (log_experiment, log_model, log_model_comparison, log_plot, .loggers) can be called unconditionally — the default BaseLogger() is a silent no-op for every method. This eliminates the if self.logging_param: truthiness checks that permeated the experiment classes.
  • CHANGEDBaseLogger (in pycaret/loggers/base_logger.py) rewritten to be the null/identity logger. Was an ABC; is now a concrete class with every hook method implemented as a silent no-op. Adds .loggers property returning [self] to replace the removed DashboardLogger fan-out. Adds log_experiment, log_model, log_model_comparison, log_plot, log_hpram_grid, log_artifact, log_sklearn_pipeline as no-op overridable hooks. Users who had a BaseLogger subclass should still work if they only override hooks (they will inherit no-op defaults for the new methods).
  • CHANGEDpycaret/loggers/__init__.py now exports only BaseLogger. Previously exported MlflowLogger, CometLogger, WandbLogger, DagshubLogger, DashboardLogger — all deleted.

CHANGED — transitional stubs (Phase 3 will replace)#

These raise a clear NotImplementedError at call time rather than at import time, so the package remains importable while killed features are progressively re-implemented.

  • CHANGED, BREAKINGshow_yellowbrick_plot stubbed in internal/pycaret_experiment/tabular_experiment.py. All plot_model calls that historically routed through yellowbrick now raise NotImplementedError with a pointer to the kill-list doc and Phase 3.
  • CHANGED, BREAKINGMlflowLogger / CometLogger / WandbLogger / DagshubLogger stubs installed in tabular_experiment.py. Any code constructing one raises NotImplementedError mentioning "pass a custom BaseLogger subclass or log_experiment=False".
  • CHANGED, BREAKINGscikitplot.metrics.plot_lift_curve / plot_cumulative_gain / plot_ks_statistic stubbed in tabular_experiment.py. plot_model('lift' | 'gain' | 'ks') will raise NotImplementedError until Phase 3 ships the Plotly replacements.
  • CHANGED, BREAKINGplotly_resampler.FigureResampler / FigureWidgetResampler stubbed in time_series/forecasting/oop.py. display_format='plotly-widget' and 'plotly-dash' raise NotImplementedError.
  • CHANGEDwith patch(...) yellowbrick mock-patches replaced with contextlib.nullcontext() in tabular_experiment.py. Preserves body indentation until Phase 3 removes the wrapper blocks entirely.

FIXED — modernization bugs#

  • FIXEDdistutils.version.LooseVersion import removed. Python 3.12 removed the distutils module. pycaret/utils/_dependencies.py rewritten to use packaging.version.Version + stdlib importlib.metadata (replaces the importlib_metadata backport).
  • FIXEDjoblib.Memory bytes_limit kwarg handling updated. joblib>=1.4 moved bytes_limit off the constructor and onto reduce_size(bytes_limit=...). FastMemory.__init__ in pycaret/internal/memory.py now strips the old kwarg and forwards it into reduce_size on each reduction.
  • FIXEDnp.NaNnp.nan. pycaret/internal/preprocess/preprocessor.py line 682. NumPy 2.0 removed the capitalised alias.
  • FIXEDsklearn.metrics._regression._check_reg_targets new signature. sklearn 1.7 inserted sample_weight as a positional parameter and expanded the return from 4 to 5 values. Custom MAPE metric in pycaret/containers/metrics/regression.py updated to pass the new arg and unpack the new return.
  • FIXEDBATS / TBATS containers guard against missing tbats. pycaret/containers/models/time_series.py: BATSContainer.__init__ and TBATSContainer.__init__ now try-import the sktime wrapper inside a try/except and set self.active = False on failure, rather than crashing the entire container registry.
  • FIXEDMatplotlibDefaultDPI rewritten in pycaret/internal/plots/helper.py. Previously went through scikitplot.metrics.plt; now talks to matplotlib directly. Fixes an ImportError at module load.

DOCS#

  • DOCSCreated docs/revamp/ directory — the authoritative narrative of the revamp. Index in README.md.
  • DOCSCreated docs/revamp/AUDIT.md — baseline inventory of 3.4.0: 62,164 LOC, monster-file hotspots, dep upper-bound audit, kill-list evidence with file paths, test landscape, headline risks.
  • DOCSCreated docs/revamp/KILL_LIST.md — every dep and subsystem being removed, with replacements and rationale. Pre-approved removals.
  • DOCSCreated docs/revamp/ROADMAP.md — phased plan (Phase 0 groundwork / Phase 1 amputation / Phase 2 modernization / Phase 3 Plotly plot rewrite / Phase 4 agent+UI API / Phase 5 docs+release). Exit criteria per phase.
  • DOCSCreated docs/revamp/DECISIONS.md — ADR-style decision log.
  • DOCSCreated docs/revamp/STATUS.md — current session status, headline metrics, next steps.
  • DOCSCreated docs/revamp/thinking/2026-04-22_session1_framing.md — scoping conversation and rejected approaches.
  • DOCSCreated docs/revamp/thinking/2026-04-22_python314_pep649_blocker.md — why Python 3.13 not 3.14 for primary dev (upstream joblib+cloudpickle blocked on PEP 649).
  • DOCSCreated docs/revamp/thinking/2026-04-22_session1_outcomes.md — quantitative/qualitative session notes intended to feed the research paper.
  • DOCSCreated docs/revamp/thinking/phase0_failure_landscape.md — 158 test failures clustered into 5 root causes with ROI-ordered fix list.
  • DOCSCreated docs/revamp/release_notes_pycaret4.md (this file) — engineering change log; user-facing notes will be generated from it.
  • DOCSCreated user-memory files under .claude/memory/ — workspace layout, kill list, version targets, revamp style, user profile, research-paper framing. Persist across sessions.

TESTS#

  • TESTSStripped from mlflow.tracking import MlflowClient imports from test_classification.py, test_regression.py, test_clustering.py, test_anomaly.py.
  • TESTSDeleted TestClassificationExperimentCustomTags class (3 mlflow-custom-tag tests) from test_classification.py.
  • TESTSDeleted TestRegressionExperimentCustomTags class (3 mlflow-custom-tag tests) from test_regression.py.
  • TESTSDeleted mlflow-specific test_clustering function from test_clustering.py. File now has a data fixture but no tests — will be populated in a later session.
  • TESTSDeleted mlflow-specific test_anomaly function from test_anomaly.py. Same state as test_clustering.py.
  • TESTSFirst post-amputation full run captured in docs/revamp/thinking/phase0_pytest_run1.log: 568 passed / 158 failed / 8 skipped in 34:26 (77.4% pass rate). Three further engine-only test files deleted after the run.

INTERNAL#

  • INTERNAL_show_versions reference to tbats left in place. Even though tbats is no longer a declared extra, pycaret/utils/_show_versions.py still lists it in its introspection table; the BATS/TBATS containers gracefully no-op when the package is missing.
  • INTERNALuv dev-dependencies migrated from [tool.uv.dev-dependencies] to [dependency-groups.dev]. The former is deprecated in current uv versions.