Repository navigation
Conversation
The Preprocessor injected target_aware only into methods that declare placement strategies, and register_representation defaults placement_strategies to (). A representation registered with supervision="optional" therefore kept its own target_aware default while y was still forwarded to it: with target_aware=False it could fit on y (target leakage despite the "y-free fit" contract), and with target_aware=True a class defaulting to False ignored it and lineage reported uses_target=False. target_aware is now passed to every optional method, and placement_strategy only to methods that declare strategies, so built-ins are unchanged. As the docs say an optional representation uses y only when target_aware=True, register_representation now rejects an optional class without a target_aware constructor parameter with a TypeError instead of letting it see y unchecked. Fixes #96
This was referenced Oct 16, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #96.
A custom representation registered with
supervision="optional"never received thePreprocessor'starget_aware. It kept its own default whileywas still passed tofit, soPreprocessor(target_aware=False)could fit it ony(target leakage in a configuration chosen to be target-free), andtarget_aware=Truewas ignored by a class that defaults toFalse.Root cause
_placement_kwargsinpretab/compose/factory.pyreturned{}for every spec withoutplacement_strategies, before it reached thetarget_usage == "optional"branch that injectstarget_aware.register_representationdefaultsplacement_strategiesto(), so only the built-in optional methods, which all declare placement strategies, receivedtarget_aware.Fix
_placement_kwargshandlestarget_usage == "optional"first: every optional spec receivestarget_aware, andplacement_strategyonly when the spec declares placement strategies. The no-strategies early return now applies only to the other kinds of spec, so the built-in methods get exactly the same keyword arguments as before.register_representationraisesTypeErrorwhen a class registered as"optional"(declared on the class or passed assupervision) has notarget_awareconstructor parameter (_accepts_target_aware), because thePreprocessorcould not switch its use ofyoff.Behaviour changes
Preprocessor'starget_aware(defaultTrue), whatever its own default. A class that defaults totarget_aware=Falsetherefore becomes target-aware under the defaultPreprocessor(), and its lineage reportsuses_target=True.register_representation(..., supervision="optional")raisesTypeErrorfor a class without atarget_awareconstructor parameter.load_entry_point_representationsskips such a plugin with aConfigWarning, as it does for any plugin that fails to register.Documentation
docs/tutorials/custom_representation.md(supervisionentry): an"optional"class must take atarget_awareconstructor parameter;Preprocessorsets it from its owntarget_aware, and registration rejects a class without one.BaseRepresentation(supervision),register_representation(supervision, andplacement_strategies:Preprocessorpassesplacement_strategyonly to a method that declares strategies),_placement_kwargs.docs/core_concepts/target_awareness.mdalready definesoptionalas "Uses the target only whentarget_aware=True", which now also holds for registered classes, and is unchanged.Tests
test_placement_optional_without_strategies_still_forwards_target_aware: an optional spec without placement strategies gets{"target_aware": False}or{"target_aware": True}and noplacement_strategy. Fails onmain, passes here.test_register_optional_representation_follows_preprocessor_target_aware[_SplitAtTarget, _SplitAtTargetOffByDefault]: for a class defaulting toTrueand one defaulting toFalse, the fitted step'starget_aware, whether itsfitusedy, and the lineageuses_targetfollow thePreprocessor'starget_aware. Fails onmain, passes here.test_register_optional_representation_requires_target_aware_parameter: registering an optional class withouttarget_aware, declared on the class or passed assupervision="optional", raisesTypeErrorand registers nothing. Fails onmain, passes here.Reproduction
Output of the script from #96 on this branch:
Checks
just test: 1442 passed, 59 skipped, 7 xfailed; coverage 93.62% (gate 90%).scripts/quickstart.pypasses.just docs: strict build succeeds.just check: all pre-commit and pre-push hooks pass (ruff format, ruff lint, prettier, file hygiene, pyright with 0 errors).Merge notes
main.Preprocessorblocks per fold) conflicts in thesupervisionentry of theregister_representationdocstring inpretab/extension.py. Keep the shared first sentence ("Inferred fromclswhen omitted.") once, followed by this PR'starget_awarerequirement and CrossFittedTransformer(Preprocessor) relearns column types and category codes per fold, unlike transform #79's text on how the declaration decides lineage and per-fold refitting.target_aware=Falsebecomes target-aware under the defaultPreprocessor, and with CrossFittedTransformer(Preprocessor) relearns column types and category codes per fold, unlike transform #79's per-block refit such a block must be recognised as target-using, or its out-of-fold rows are encoded by an all-data fit. The testtest_optional_class_follows_the_preprocessor_target_aware_across_foldsintests/extension/test_registered_cross_fitting.py(a file CrossFittedTransformer(Preprocessor) relearns column types and category codes per fold, unlike transform #79 creates) pins the two fixes together. It is added by whichever of the two PRs merges second. Itstarget_aware=Truecase fails with either PR alone. With both branches combined, the docstring resolved as above and the test added, the full test suite passes (1458 passed, 59 skipped, 7 xfailed).This change was previously part of #97, which is closed in favour of one pull request per issue.