Should deprecation warnings be re-enabled for all code by default?

The Python 3.10 integer-narrowing change continues to catch people unawares. Here are four GitHub issues/PRs related to code that started crashing when run under Python 3.10. The interesting thing is that all four of these are from the past two months:

The thing is that these issues could have been caught much earlier. All of this code was previously being run, presumably regularly and presumably by multiple people, under Python versions 3.9, 3.8, etc… Narrowing conversions of floats to integers were already deprecated in those versions, and could have produced visible DeprecationWarning messages… were those messages not disabled by default!

I sort of get the arguments for disabling them. DeprecationWarnings, it can be argued, aren’t meant for endusers — they’re meant for the developers of the code in question, so why distract/bother the enduser with them? There’s nothing they can do about those warnings, right?

Both of those assertions are incorrect, though.

  1. DeprecationWarnings absolutely are of interest to the enduser, because ultimately they’re the ones running (and depending on) the code that’s making use of deprecated features (no matter how indirectly). And ultimately, the software is going to fail for them if those deprecations are not addressed. I’d argue endusers are far more invested in code stability than the code’s developers are, when it comes right down to it.

  2. There is absolutely something that endusers can do about DeprecationWarnings: They can file bugs, they can report them to the developers, they can agitate for them to be addressed so that, when those deprecations eventually become errors, that doesn’t translate into a sudden failure of their critical application.

Also, for better or for worse the reality is that endusers will always represent a more heterogeneous test environment than any the developer can provide for their own testing. We rely on endusers to report bugs running our code on platforms, with dependency versions, and in situations that our testing never evaluated.

Many independent developers with limited resources at their disposal don’t employ a comprehensive, multi-version, multi-platform testing infrastructure. And in those cases, testing is often limited to the oldest supported versions of their dependencies in order to limit use of newer features that prevent their code from being backwards-compatible with those older versions. Which means that it’s often the endusers, not the developers, who are the first ones to run some code under the most recent Python releases.

When they do, they should be made aware of any deprecated functionality being relied upon in that code, as a first step towards getting that issue addressed.

As an enduser, try running basically any software written in Python with PYTHONWARNINGS=always set in the process environment. Whenever I do that, I’m always amazed at the flood of messages, primarily DeprecationWarnings, that spews from the terminal.

The reason there are so many uses of deprecated functionality is that nobody is paying attention to them, and therefore nobody is addressing them! And that translates into painful surprises down the road, when things that should have been fixed ages ago suddenly blow up in our collective faces.

6 Likes

Have you raised bugs for them all? How quickly do those bugs get fixed? Is it tolerable for you to run with PYTHONWARNINGS=always permanently switched on?

Personally, I’ve had deprecation warnings appear for me as an end user in the past, reported them, and had very slow results. In the meantime those warnings have caused issues for me (unexpected output causing problems for automation scripts, for example, as well as just the routine annoyance of noisy commands telling me something I already know). And switching those warnings off once I’ve reported them is far from trivial.

I just tried running pip with PYTHONWARNINGS="always" and got the warnings

...\Programs\Python\Python310\lib\site-packages\pip\_internal\locations\_distutils.py:9: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
...\Programs\Python\Python310\lib\distutils\command\install.py:13: DeprecationWarning: The distutils.sysconfig module is deprecated, use sysconfig instead

The first one we (the pip maintainers) know about and have a transition plan for. What would we tell our users if they had to see that message every time they ran pip until the transition was complete?

The second one comes from distutils itself. Who is supposed to fix this for me? As a pip maintainer, what am I supposed to say to my users when they report this? Upgrade to a newer version of Python?

In principle, this makes some sense. But in practice, there are far too many cases where users would be overwhelmed by messages they simply can’t do anything about.

Maybe encouraging more of your users to occasionally run with PYTHONWARNINGS="always" and let you know what they encounter would be useful. But forcing everyone to act as your testing team, with no easy opt-out, seems like it’s too much, to me.

2 Likes

Thanks, Paul. You raise some good points.

For them all? No. For the ones I have filed bugs (or, more often, submitted PRs), it’s been a very mixed bag. Some were merged quickly. Some got no attention at all. I’m sure at least one was received with a shrug and an eye roll. I don’t think I’ve ever had anyone respond negatively, though. It’s just degrees of enthusiasm (or lack).

No, it definitely isn’t, and I wouldn’t propose that as a default, either. PYTHONWARNINGS=once (or is it first?) is the default I’d suggest. always is good for getting a feel of just HOW dependent on deprecated code something is, but it’s far too unnecessarily noisy to be the default.

That’s a concern, I agree. But I also think there’s something of a catch-22, with the current situation. Because the warnings are normally hidden, and because something deliberate has to be done to even see them, the low-hanging fruit of “solutions” is to say, “Well, then just don’t do that!” Why expend effort to address something that doesn’t affect anyone unless they go asking to be bothered by it?

Whereas, if the messages showed up for ALL of the developers AND users, every time, devs might be more inclined to address them. If only to stop more bug reports from coming in about them.

Having the messages hidden by default sends the message, “this is unimportant”. There’s no reason to expect already-overtaxed developers to expend any cycles on it. But developers let Python shield them from the warnings at their own peril, as the rocky road many of us have had to Python 3.10 compatibility demonstrates.

I don’t know. How about, “We have a transition plan, and a future version of pip will eliminate that warning.”? Seems reasonable to me.

What will you tell them when they try to run an un-transitioned pip with Python 3.12, and it fails with a ModuleNotFound exception?

I’d have expected, “Upgrade to the newest version of pip.” Is pip in older Pythons going to continue to depend on distutils? I thought the plan was to vendor everything into either sysutils or pip itself? So as long as they’ve updated both, the warnings should go away under every version of Python… no?

Is it a good idea to enable all warnings (first occurrence) for alpha/beta/RC releases of Python? Probably not big enough of a test matrix. What other ways do we know when Python is being invoked during development of an application?

2 Likes

AFAIK they are enabled by default on the debug build.