I used to be of the opinion that it makes sense to delay a deprecation until a replacement has matured. I’ve since learned that a replacement often doesn’t mature until the functionality it replaces is marked as deprecated, creating the incentive for adoption. As a result, my default action is to deprecate a behavior as soon as it’s known to be deprecated and there exists a presumed-suitable replacement, as long as one is prepared to back out the deprecation or iterate quickly to correct for any shortcomings in the migration to the replacement.
In the case of importlib.resources
the implementation has had time to mature, being almost two years old and present in two Python versions.
The CPython backward-incompatible guidance policy doesn’t give any direction regarding the maturity or pace of changes other than for the “two minor release” window.
If library authors are concerned about the support matrix, they have an easy option: just rely on importlib_resources>=1.3
. It’s simple and straightforward, and when they get to a world where only Python 3.9 and later is supported, they can simply switch to the stdlib.
Agreed. It would have been preferable, knowing all that we know now, to leave importlib.resources
out of the stdlib until the traversable API was present. Perhaps the module should have been declared as provisional. Unfortunately, no one recognized the crucial deficiency (and other more minor deficiencies) of that implementation until it was too late. I don’t blame anybody, but am merely working within the constraints given.
It sounds like there’s widespread consensus that this project should hold itself to a standard higher than that given in the policy. In particular, I believe this is what is proposed for this change:
The backward-incompatible change should not be made until the replacement is available in all supported Python versions, and the DeprecationWarning should not be introduced until as late as possible (two minor releases prior to the removal).
Should this policy be applied to all backward-incompatible changes in the standard library? If not, under what circumstances should this more conservative approach apply? Should it also apply to backports of modules in the standard library?
Separately, the guide does provide for having a PendingDeprecationWarning
for when a change is not known when it will be removed. That could be employed here. Unfortunately, the policy doesn’t give guidance on when that warning should be employed.
There’s some guidance in this thread, but it basically boils down to don’t use PendingDeprecationWarning
. Although it does look as if the proposed _deprecate
decorator would issue PendingDeprecation until N-1 and only issue Deprecation on N-1, somewhat in conflict with PEP 387.
Thanks to the flexibility of third-party packaging, there’s quite a bit of control over versions. Third-party packages can iterate quickly and empower libraries and environments to choose their path (silence, pin, migrate, …). Admittedly, it’s harder for libraries that want to avoid conflicts with other libraries that may have different notions (e.g. flake8
couldn’t pin to importlib_resources==5.2
but probably could pin to importlib_resources<5.3
, at least until some crucial feature was added to 5.4+).