You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CausalML learners take fit(X, treatment, y, ...), which puts y third. sklearn.pipeline.Pipeline calls the final estimator's fit(X, y) positionally, so today a CausalML learner can't be a Pipeline step without an adapter — the problem reported in #854.
The v1.0 roadmap RFC lists this under M1 — Foundation & stability as the one intentional breaking change: adopt fit(X, y, treatment, ...).
Reordering two required positional arguments can't be done in one step. y and treatment are both same-length arrays, so a straight swap would silently mis-train existing positional callers with no TypeError to catch it. So this is a two-step deprecation, and this epic tracks it end to end.
Step one has landed (#975): positional order is unchanged, but passing treatment/y positionally emits a FutureWarning pointing callers at keyword arguments — fit(X, y=y, treatment=treatment) — which are order-independent and therefore safe across the flip.
The rule
One rule, applied uniformly: X, then y, then treatment, and every other parameter keeps its relative position. It is implemented in causalml/inference/_arg_order.py as v1_order(), derived per method from that method's own signature, so the target order is machine-checkable rather than hand-maintained:
method
today
v1.0
meta-learner fit
(X, treatment, y, p, …)
(X, y, treatment, p, …)
predict
(X, treatment, y, p, …)
(X, y, treatment, p, …)
CausalTreeRegressor.fit
(X, treatment, y, sample_weight, …)
(X, y, treatment, sample_weight, …)
IVRegressor.fit
(X, treatment, y, w)
(X, y, treatment, w)
BaseDRIVLearner.fit
(X, assignment, treatment, y, …)
(X, y, treatment, assignment, …)
predict is included deliberately. Its current order doesn't block Pipeline, since predict(X) already works — but flipping only fit would leave v1.0 with the same two arguments in opposite positional orders on one class. Methods that don't take treatment/y at all, such as BaseRLearner.predict, are untouched.
Why the sequencing matters
A deprecation window is one-shot. Anything whose positional order changes at v1.0 has to warn in the same release as the shim, or it needs a second deprecation cycle of its own. That is why the "close the window" issues below are not optional cleanup — they gate the flip, and they must ship alongside #975 rather than with it.
The flip itself is inherently breaking and cannot be staged: once a signature is reordered, old positional calls break silently. It therefore lands as a single change on the v1.0 line, per-family checklist and all.
Child issues (dependency-ordered)
Close the deprecation window — ships with the warning release:
Reordering alone does not make a learner a drop-in Pipeline step: treatment still has to be threaded through sklearn's metadata routing. #854 stays open until that lands.
Open questions
UpliftTreeClassifier.fit takes (X, treatment, y, X_val, treatment_val, y_val, sample_weight, check_input). The rule above moves the first triple but leaves the validation triple as X_val, treatment_val, y_val — internally inconsistent. Reorder the *_val arguments too, or leave them and document the asymmetry?
Sensitivity.get_prediction / .get_ate_ci / .get_potential_outcome_predictions take (X, p, treatment, y) — a third shape, with p second. In scope for the flip, or left alone as evaluation-side helpers?
Summary
CausalML learners take
fit(X, treatment, y, ...), which putsythird.sklearn.pipeline.Pipelinecalls the final estimator'sfit(X, y)positionally, so today a CausalML learner can't be a Pipeline step without an adapter — the problem reported in #854.The v1.0 roadmap RFC lists this under M1 — Foundation & stability as the one intentional breaking change: adopt
fit(X, y, treatment, ...).Reordering two required positional arguments can't be done in one step.
yandtreatmentare both same-length arrays, so a straight swap would silently mis-train existing positional callers with noTypeErrorto catch it. So this is a two-step deprecation, and this epic tracks it end to end.Step one has landed (#975): positional order is unchanged, but passing
treatment/ypositionally emits aFutureWarningpointing callers at keyword arguments —fit(X, y=y, treatment=treatment)— which are order-independent and therefore safe across the flip.The rule
One rule, applied uniformly:
X, theny, thentreatment, and every other parameter keeps its relative position. It is implemented incausalml/inference/_arg_order.pyasv1_order(), derived per method from that method's own signature, so the target order is machine-checkable rather than hand-maintained:fit(X, treatment, y, p, …)(X, y, treatment, p, …)predict(X, treatment, y, p, …)(X, y, treatment, p, …)CausalTreeRegressor.fit(X, treatment, y, sample_weight, …)(X, y, treatment, sample_weight, …)IVRegressor.fit(X, treatment, y, w)(X, y, treatment, w)BaseDRIVLearner.fit(X, assignment, treatment, y, …)(X, y, treatment, assignment, …)predictis included deliberately. Its current order doesn't blockPipeline, sincepredict(X)already works — but flipping onlyfitwould leave v1.0 with the same two arguments in opposite positional orders on one class. Methods that don't taketreatment/yat all, such asBaseRLearner.predict, are untouched.Why the sequencing matters
A deprecation window is one-shot. Anything whose positional order changes at v1.0 has to warn in the same release as the shim, or it needs a second deprecation cycle of its own. That is why the "close the window" issues below are not optional cleanup — they gate the flip, and they must ship alongside #975 rather than with it.
The flip itself is inherently breaking and cannot be staged: once a signature is reordered, old positional calls break silently. It therefore lands as a single change on the v1.0 line, per-family checklist and all.
Child issues (dependency-ordered)
Close the deprecation window — ships with the warning release:
treatment-before-ymethods #981 — extend the shim to the remaining public methods that taketreatmentbeforeytests/to keywordfit/predictcalls (917 FutureWarnings) #982 — migratetests/to keyword callsfit/predictcalls #983 — migratedocs/notebooks and guides to keyword callsfit()argument-order migration guide + changelog entry #984 — migration guide +docs/changelog.rstentryThe flip — v1.0:
(X, y, treatment, ...)and delete the deprecation shim #985 — reorder every signature to(X, y, treatment, …)and delete the shimActually deliver #854:
treatmentreach a learner inside a Pipeline #986 — sklearn metadata routing sotreatmentcan reach a learner inside aPipelineReordering alone does not make a learner a drop-in Pipeline step:
treatmentstill has to be threaded through sklearn's metadata routing. #854 stays open until that lands.Open questions
UpliftTreeClassifier.fittakes(X, treatment, y, X_val, treatment_val, y_val, sample_weight, check_input). The rule above moves the first triple but leaves the validation triple asX_val, treatment_val, y_val— internally inconsistent. Reorder the*_valarguments too, or leave them and document the asymmetry?Sensitivity.get_prediction/.get_ate_ci/.get_potential_outcome_predictionstake(X, p, treatment, y)— a third shape, withpsecond. In scope for the flip, or left alone as evaluation-side helpers?Window length. How many minor releases between the warning and the flip?Answered: releases are quarterly — 0.18.0 Sep 2026 (ships the warning), 0.19.0 Dec 2026, 0.20.0 Mar 2027, v1.0 Jun 2027 (the flip). Three minor releases, roughly nine months. Published in the migration guide and changelog by Publish the release schedule and the #854 deprecation window #993, so Flip every signature to(X, y, treatment, ...)and delete the deprecation shim #985 is no longer blocked.Refs #854. Part of the v1.0 M1 milestone (#938).