fix: withdraw the plain-string deprecation - #16
Merged
Conversation
0.5.0 made plain strings emit DeprecationWarning and announced removal in 1.0.0. That was wrong.
Strings are now permanently supported, and 1.0.0 will not remove them.
Every comparable library passes options as plain strings, and none export enums: scikit-learn
(KMeans(init="k-means++", algorithm="lloyd")), numpy (np.pad(mode="constant")), scipy
(linkage(method="single")), and both SOM libraries, minisom (neighborhood_function="gaussian") and
sompy (normalization="var"). scikit-learn validates them at runtime through StrOptions, a constraint
rather than a type. Removing the string form would have made this the only library in its ecosystem
to reject mode="batch".
The argument originally made for enums, from Viafore's Robust Python ch. 8, is about preventing typos
inside a codebase, and he adds a "When Not to Use" section. The benefit he claims is that a type
checker rejects a wrong value, and the Literal unions added in 0.4.0 already deliver exactly that
with strings still working: mode="bacth" is a type error while mode="batch" is not. The deprecation
bought nothing that was not already had.
The enums stay. They cost nothing, some callers prefer them, and removing them would be a second
reversal in two releases.
`warn_if_string` and its four call sites are gone. The tests that wrapped string calls in
`pytest.warns` are unwrapped, and a new test asserts the *absence* of any warning at every call site
under `simplefilter("error")`, so the withdrawal cannot be quietly undone.
The decision was originally made without checking what comparable libraries do.
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.
0.5.0 deprecated the plain-string options and announced removal in 1.0.0. That was wrong, and this
withdraws it. Strings are permanently supported.
Why it was wrong
Every comparable library passes options as plain strings, and none export enums at all. Measured
against the installed versions, not recalled:
KMeans(init="k-means++", algorithm="lloyd")np.pad(mode="constant"),norm(ord="fro")linkage(method="single"),minimize(method="BFGS")neighborhood_function="gaussian",topology="rectangular"normalization="var",neighborhood="gaussian"scikit-learn validates them at runtime with
StrOptions— a constraint, not a type. minisom is theclosest peer, and python-som's method names already mirror it (
activate,winner,quantization,quantization_error,get_weights).Removing the string form would have made this the only library in its ecosystem to reject
mode="batch".The book said less than I claimed
The original design cited Viafore, Robust Python, ch. 8. Re-read, his case is about preventing typos
inside a codebase, and he includes a "When Not to Use" section. The benefit he actually claims is
that a type checker rejects a wrong value — and the
Literalunions added in 0.4.0 already deliverexactly that, with strings still working:
So the deprecation bought nothing that was not already had, and cost ecosystem divergence.
What changes
warn_if_stringand its four call sites are removed.pytest.warnsare unwrapped.warnings.simplefilter("error")rather than the removedpytest.warns(None), so any warning at allfails. The withdrawal cannot be quietly undone.
The enums stay. They cost nothing, some callers prefer them, and removing them would be a second
reversal in two releases. Anyone who migrated while 0.5.0 was current keeps working code.
Where this leaves the roadmap
refactor/enums-onlyis dropped from 1.0.0. With strings staying, what remains breaking is thin —keyword-only arguments, removing two setters, removing pre-0.3.0 private aliases, dropping Python 3.10
after its October 2026 EOL — and the plan already warned against freezing an interface before it has
been used. So 0.6.0 adds the estimator API additively and 1.0.0 waits for real use of it.
On process
The deprecation was decided without checking what comparable libraries do. Reversing one release later
is cheap; discovering it at 1.0.0, after breaking every user, would not have been.
Verification
383 tests, 100% coverage, ruff /
ruff format/mypy --strictclean,mkdocs build --strictexits0, architecture profile
--strictpasses. Every call site exercised with plain strings under-W error::DeprecationWarning.