2026-04-22
Session 3: Functional API killed; 4.0 is OOP-only
Engineering log for session 3.
Baseline: end of session 2. Environment: unchanged.
Theme: the user made the final 4.0 call — "nobody will migrate 3 → 4. 4 in my mind is totally new thing. I really would like to get rid of 90% tech debt now." This session deletes the module-level functional API entirely, leaving the sklearn-compatible Experiment class hierarchy as the single canonical surface.
BREAKING — functional API removed wholesale#
REMOVED, BREAKING—pycaret.classification.setup,compare_models,create_model,tune_model,ensemble_model,blend_models,stack_models,plot_model,evaluate_model,interpret_model,calibrate_model,optimize_threshold,predict_model,finalize_model,deploy_model,save_model,load_model,automl,pull,models,get_metrics,add_metric,remove_metric,get_logs,get_config,set_config,save_experiment,load_experiment,get_leaderboard,set_current_experiment,get_current_experiment,dashboard,convert_model,check_fairness,create_api,create_docker,create_app,get_allowed_engines,get_engine,check_drift— all 40 module-level functions gone. Filepycaret/classification/functional.pydeleted (3,323 LOC).REMOVED, BREAKING—pycaret.regressionfunctional API — 38 module-level functions,pycaret/regression/functional.pydeleted (3,033 LOC).REMOVED, BREAKING—pycaret.clusteringfunctional API — 23 module-level functions,pycaret/clustering/functional.pydeleted (1,461 LOC).REMOVED, BREAKING—pycaret.anomalyfunctional API — 18 module-level functions,pycaret/anomaly/functional.pydeleted (1,256 LOC).REMOVED, BREAKING—pycaret.time_seriesfunctional API — 26 module-level functions,pycaret/time_series/forecasting/functional.pydeleted (2,260 LOC).
Total LOC dropped in this session: ~11,333 lines of pass-through wrappers.
BREAKING — class renaming#
CHANGED, BREAKING—TSForecastingExperimentrenamed toTimeSeriesExperimentin the public API. The cleaner name matches the task's module name. The legacy class (pycaret.time_series.forecasting.oop.TSForecastingExperiment) still exists as an internal implementation detail the new wrapper delegates to during migration.
ADDED — 4 new task subclasses + stateless persistence#
ADDED—pycaret.tasks.RegressionExperiment(sklearn-compatible,estimator_type="regressor"; delegates to legacy_NonTSSupervisedExperimentduring transition).ADDED—pycaret.tasks.ClusteringExperiment(inheritsUnsupervisedExperiment; addsassign_model).ADDED—pycaret.tasks.AnomalyExperiment(inheritsUnsupervisedExperiment; addsassign_model).ADDED—pycaret.tasks.TimeSeriesExperiment(inheritsSupervisedExperiment; addscheck_stats; overridesfit()for univariate time-series inputs).ADDED—pycaret.core.supervised.SupervisedExperiment— intermediate base that hosts supervised-only verbs (compare_models,tune_model,ensemble_model,blend_models,stack_models,calibrate_model,finalize_model,interpret_model,automl,get_leaderboard). Extracted fromExperimentso unsupervised tasks don't inherit verbs they can't implement.ADDED—pycaret.core.unsupervised.UnsupervisedExperiment— intermediate base that addsassign_model. Tells the legacy engine via an override that supervised-coercion is not needed infit.ADDED—pycaret.persistence— stateless top-levelsave_model(model, path)/load_model(path)utilities. No experiment required, no globals, no mutation. Re-exported aspycaret.save_model/pycaret.load_model.
CHANGED — legacy module paths thinned#
Each pycaret/{module}/__init__.py reduced from a 40-entry re-export list (~90 LOC with __all__) to a ~15-line docstring plus a single-line from pycaret.tasks.{module} import {Task}Experiment:
CHANGED—pycaret/classification/__init__.pythinned (88 LOC → 20).CHANGED—pycaret/regression/__init__.pythinned (83 LOC → 13).CHANGED—pycaret/clustering/__init__.pythinned (53 LOC → 14).CHANGED—pycaret/anomaly/__init__.pythinned (43 LOC → 14).CHANGED—pycaret/time_series/__init__.pythinned (59 LOC → 16).CHANGED—pycaret/time_series/forecasting/__init__.pycreated as a deep-import path for the legacy class (10 LOC).CHANGED—pycaret/__init__.pyrewritten with a canonical-API docstring and top-levelsave_model/load_modelre-exports.CHANGED—pycaret/core/experiment.pyExperiment base had supervised-only verbs extracted intoSupervisedExperimentsubclass; unsupervised task-subclass setup kwargs now strip supervised-only params (target,train_size,fold,fold_strategy,transformation,remove_outliers,feature_selection) which the legacy unsupervisedsetup()doesn't accept.
REMOVED — state machinery#
REMOVED, BREAKING—pycaret/core/state.pydeleted.current_experiment(),set_current_experiment(),reset_current_experiment(),require_current_experiment()— with no functional API to serve, these had no purpose. TheContextVar-backed current-experiment machinery is gone entirely.REMOVED, BREAKING—set_current_experiment/get_current_experimentpublic functions in every task module. They backed the functional API's implicit-experiment model; that model is gone.
REMOVED — tests that exercised the functional API#
TESTS, BREAKING— 22 classification/regression/clustering/anomaly/misc test files deleted:test_classification.py,test_classification_plots.py,test_classification_tuning.py,test_regression.py,test_regression_plots.py,test_regression_tuning.py,test_clustering.py,test_anomaly.py,test_multiclass.py,test_optimize_threshold.py,test_overflow.py,test_preprocess.py,test_probability_threshold.py,test_supervised_predict_model.py,test_tune_model.py,test_convert_model.py,test_pipeline.py,test_memory.py,test_utils.py,test_utils_datetime.py,test_persistence.py,test_persistence_experiment.py. All were functional-API-coupled and would fail to import in 4.0.TESTS, BREAKING— 19 time-series test files deleted:test_time_series_{base,blending,exogenous,feat_eng,indices,metrics,models,plots,preprocess,setup,stats,tune_base,tune_grid,tune_random,utils,utils_forecasting,utils_forecasting_pipeline,utils_plots}.py, plus thetime_series_test_utils.pyhelper. Will be re-authored in OOP style as each TS verb is rewritten natively.TESTS—tests/conftest.pyrewritten. The 3.x_CURRENT_EXPERIMENTreset fixture and the TSForecastingExperimentload_setupfixture are gone. File reduced from 152 LOC to 21.
ADDED — OOP test suite#
ADDED—tests/test_e2e_oop.py— end-to-end smoke tests covering all 5 tasks via the new OOP API. Includes:- Classification e2e (setup + create_model + compare_models + predict_model + save/load roundtrip + event-stream verification)
- Regression e2e (compare + predict)
- Clustering e2e (create + assign)
- Anomaly e2e (create + assign)
- API introspection surface (static
list_models/describe_model/list_metrics/describe_setup_paramsplus JSON round-trip) - Event-stream subscriber fan-out
ADDED—tests/test_core_architecture.pyextended with:test_tasks_package_exports_all_five_task_subclassestest_legacy_import_paths_re_export_new_classestest_all_task_subclasses_are_sklearn_compatibletest_top_level_save_load_model_roundtriptest_functional_api_is_gone— asserts the absence ofsetup/compare_models/set_current_experimenton every task module (regression canary)
CHANGED—tests/test_models.pyrewritten to the OOP pattern (exp = ClassificationExperiment(target=...).fit(df)instead ofexp = ClassificationExperiment(); exp.setup(df, target=...)). ImportsTimeSeriesExperiment(4.0 name) instead ofTSForecastingExperiment.create_model(id).pipelineshape used for equality checks.TESTS— All 32 tests pass on Python 3.13 + sklearn 1.7.2 in ~2 minutes. 100% green vs. 77% green at end of session 1 (on a smaller, OOP-native suite).
DOCS#
DOCS, BREAKING—README.mdrewritten. Removes the 3.x positioning ("low-code ML library"), replaces it with the 4.0 engine framing (sklearn-composable, typed results, event stream, engine for React UI + agents). Quickstart shows the OOP pattern for all 5 tasks. "What's not in 4.0" section is explicit about the kill list. New "Who PyCaret 4.0 is for" section.DOCS— Release notes (this file) updated with the session-3 block.
INTERNAL#
INTERNAL—pycaret.tasks.__init__.pyexports all 5 task subclasses.INTERNAL—pycaret.core.__init__.pyexportsSupervisedExperimentandUnsupervisedExperimentalongside the task-agnosticExperimentbase.INTERNAL— Transition pattern unchanged from session 2: each task subclass's_build_legacy_experiment()still returns the 3.x god-class instance, and every verb delegates. Replacement with native sklearn.pipeline implementations happens verb-by-verb in subsequent sessions; the public API is stable from here on.
Session delta summary#
| Metric | Session 2 end | Session 3 end | Δ |
|---|---|---|---|
| pycaret/ source LOC | ~60,700 | ~49,400 | −11,300 |
| Test files | 45 | 4 | −41 |
| Test pass count | 568 (of 734) | 32 (of 32) | — |
| Test pass rate | 77% | 100% | +23pp |
| Public module-level functions | 145 (functional API) | 0 | −145 |
| Canonical APIs | 2 (functional + OOP) | 1 (OOP) | −1 |
| Module-level mutable state | 5 ContextVars / globals | 0 | −5 |