[Twisted-Python] [RFC] Deprecation Policy
![](https://secure.gravatar.com/avatar/1327ce755b24b956995d68accae3eab2.jpg?s=120&d=mm&r=g)
Hello everyone, Now that the release is out[1], I'd like to start work on fixing #1216 -- official deprecation policy. There's one proposed policy at http://twistedmatrix.com/trac/wiki/CompatibilityPolicy, there's also one mentioned in the ticket itself: deprecate in release N, remove in release N+1. Glyph has at one point expressed a desire for time-based deprecation.[2] I think these are all the questions we need to answer: - Is it time-based or release-based? - How long for? - Do we grade deprecations? How? - Which code is subject to this policy? CompatibilityPolicy suggests release-based deprecation that is graded over 4 releases: release N PendingDeprecationWarning, N+1 DeprecationWarning, N+2 DeprecationError, N+3 remove the functionality. Ticket #1216 suggests a release-based deprecation policy that is not graded and over 1 release: release N, add DeprecationWarning, release N+1, remove the functionality. Important factors to bear in mind: - Maintaining deprecated APIs brings a cost to developers when they maintain code. - Removing APIs brings a cost to users when they choose to upgrade. - We will probably always be changing APIs and making mistakes when we change them. Now, here's what I think. * Release-based, not time-based. Releases are easy to track, dates are less so. This is as true for Twisted programmers as it is for sysadmins & other Twisted users. I think that whatever problems are solved by time-based deprecation are better solved by regular releases. Our releases should, of course, be time-based. But that's another discussion. * Two release deprecation length. That is: release N, DeprecationWarning; release N+1, DeprecationWarning; release N+2, remove the functionality. This is enough to allow users to upgrade their version of Twisted incrementally. Trial has been doing one release for quite a while now, and I can't recall any complaints about breaking compatibility in released code. Micro-releases don't count. * No grading I think the DeprecationWarning vs PendingDeprecationWarning vs DeprecationError is too much hassle. Just say "next release" or "in two releases time". * All "public" code and command-line tools should be covered. Things marked as deprecated at the time of the 8.0 release should be grandfathered so as to be safe for removal. Anything else will get too confusing. The removal of the API stability markers agrees with this. Everything is public unless it starts with one underscore.[3] Most importantly, we should have a policy, we should all agree and as much of the policy as possible should be implemented in Python. This bug has been open for years now, and it is frustrating for the policy to change under one's feet or to disagree with other developers on something so fundamental. "Explicit is better than implicit". I'm sending this now because the 8.0 release is settling down and we have a sprint coming up where it might be easier to resolve this quickly. jml [1] I'm so happy. [2] http://twistedmatrix.com/trac/ticket/2352 [3] This hurts. t.trial.util doesn't begin with an underscore.
![](https://secure.gravatar.com/avatar/52cff2b66b9e291797f15f0c1b3491b8.jpg?s=120&d=mm&r=g)
On 2008.04.18 15:06:10 +1000, Jonathan Lange wrote:
As a user, I don't see much difference between a PendingDeprecationWarning and a DeprecationWarning. Or between a DeprecationError and the code being removed. Simple is good.
Now, here's what I think.
* Release-based, not time-based.
Now that version numbers are based on the year, there's not a big difference. For example, if you wanted to guarantee at least a year of DeprecationWarning before removing a feature, you could implement that by saying that if the warning goes in in 8.x, then the feature can come out in 10.0. Or vice-versa. -- David Ripton dripton@ripton.net
![](https://secure.gravatar.com/avatar/869963bdf99b541c9f0bbfb04b0320f1.jpg?s=120&d=mm&r=g)
* David Ripton <dripton@ripton.net> [2008-04-18 06:13:13 -0700]:
A PendingDeprecationWarning is not visible by default, so users of an application won't be inundated with DeprecationWarning messages they can do nothing about; but a developer can turn them on in order to check if his application is using any deprecated APIs. -- mithrandi, i Ainil en-Balandor, a faer Ambar
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
On 18 Apr, 05:06 am, jml@mumak.net wrote:
Sorry for the delay. Due to a miscommunication, I thought that Chris would be the one writing up our meeting notes and announcing this. After I realized I was the one who was supposed to be doing it, I wanted to write up something official-sounding on the wiki first, but of course, there's never enough time. So here's a rough cut at the policy that we (the current "TSF board", such as it is: chris, me, JP, and itamar) agreed on at the sprint in Cambridge. Thanks, Jonathan, for motivating this; we've needed a clear statement for a long time. Someone (and this will probably be me) needs to make a complete and unambiguous index of official Twisted policy and put it together somewhere, probably on the wiki, at least at first.
I think these are all the questions we need to answer:
The proposed policy does break down as a list of answers to these questions, so one point at a time:
- Is it time-based or release-based?
Both. There will be a minimum amount of time and a minimum number of releases before a deprecated feature may be removed.
- How long for?
Every deprecation must last for a minimum of 2 releases and a minimum of one year. Of course, anyone who wants to keep maintaining deprecated APIs for longer than that may do so. I know this is somewhat longer than you've suggested, but at the meeting we ran down a laundry list of real-world usages of Twisted and pretty much nobody upgrades Twisted more than once per year. In fact, once per 2 years seems to be the average, and that's a fairly ambitious estimate. The objective of providing a year-long deprecation period is to allow a user who is performing their bi-yearly Twisted upgrade to do so with no more than 2 intermediary upgrades.
- Do we grade deprecations? How?
There will be three phases of deprecation. When a deprecation is first introduced (in trunk) the "deprecation counter" will be at 3. When that deprecation sees its first release, it decrements to 2. Deprecations at levels 3 and 2 will be PendingDeprecationWarning. When that same deprecation sees its second release after a 6-month period, the counter decrements to 1, and finally, after a second 6-month period, it decrements to 0 and can be removed. Deprecations with a counter at 1 and at 0 (if they still exist) should emit a DeprecationWarning. The counter may not move down past 2 until *all instances of the emitted warning* have been removed from the Twisted test suite, with the exception of tests specifically for the deprecated functionality itself (i.e. tests that call assertWarns). The reason that this is described as a counter rather than primarily in terms of (Pending)DeprecationWarning is that this was a subject of intense debate during the meeting. There is definitely a consensus that the Python warnings system is not a sufficient tool we have to deal with the kind of notifications that we want to provide. There is also a consensus that it is the only tool available. So, let me provide some more detail on the desired behavior here. The idea behind using PendingDeprecationWarning is that *users* of a piece of software which depends on Twisted should, in principle, be able to upgrade Twisted by one version without seeing any error output. However, *maintainers* of that software should immediately see all the warnings when they test with a new release. Trial should change to show all PendingDeprecationWarnings by default. However, this might be impractical due to other uses of PendingDeprecationWarning - if that is the case, Twisted should include its own warning class. It may be helpful to do that in order to include the additional metadata required for an automated deprecation workflow, however. The desired deprecation workflow is: * Twisted developer deprecates functionality, by adding a warnings.warn(TwistedDeprecationWarning(some useful metadata)) to the code. * The release process automatically runs "update-deprecations" over the codebase, updating the deprecation counters in the developer-supplied metadata appropriately. The release goes out. (Ideally this would be done without actually having to modify the whole codebase, updating a central deprecation / release index.) * Another release happens that sets some counters to zero. * A developer drops support for some deprecated functionality, confident in their ability to do so by observing the zero (or negative) value for the counter. An obvious remaining piece of work to implement this final policy is to define some temporary manual things that we can do until such a tool is implemented, and implement the tool itself as soon as possible. I don't believe any tickets have yet been filed for this, and *that* I am leaving in our venerable release manager's court, since this is all a part of the release process except for the fairly minor change to trial. However, in the absence of any tools, this policy does apply now, it will just be a bit of a pain to work out where the counter stands on any particular deprecation until we've got some more metadata to help us.
- Which code is subject to this policy?
All Python code released in Twisted, with the exceptions of private modules and test modules. Only code which has been present in a release needs to be deprecated. Anything which was added after the last release and has not yet been present in any other release may be modified at will. (We try to keep trunk stable, but this only applies to code that was relying on features in previous releases.) I think that CompatibilityPolicy's explanation of an "incompatible change" explains this. Users: do not import anything from a package named "test", or any name (module, class, or function) which begins with "_"; bears will eat you. This code may change at any time. (Not a part of the policy: I personally want to add some caveats here, where users of Twisted can ask for a grace period on private APIs that people actually needed to use, but I think for now let's err on the side of allowing the deprecation - I don't want to encourage people to use private APIs. Users: if you find that there are things you can't do with the public APIs and you really need a grace period to upgrade your applications, please speak up. Eventually, I'd like to have a very aggressive "you can't even import (or invoke) this if it's private" regime where users can't accidentally use private functionality without first seeing a runtime error of some kind that they have to explicitly silence, as with my "pyexport" hack. Once we've done *that* we should definitely have a zero-tolerance policy on supporting private stuff, though...) There's obviously some work to do here to make this policy easy and convenient to follow. This needs to be edited, CompatibilityPolicy updated, and prominently linked. We need someone to write up at least two different summaries: one for maintainers of projects using Twisted ("What kind of compatibility should I expect from Twisted releases?") one for Twisted contributors ("How do I add a deprecation? When can I remove it?") and maybe one for users and one for packagers, too. We need some tools to help us update deprecations. We need trial to change so that developers are notified earlier than their users. Do I hear any volunteers...? :)
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
On 06:50 am, glyph@divmod.com wrote:
All Python code released in Twisted, with the exceptions of private modules and test modules.
To be specific, this means code actually present in the Twisted release, which does not, for example, include web2. I guess that's still be an exception. So this doesn't just mean "everything in the repository". (Maybe we should do a release of web2 and just admit people are actually using it. But that's a totally separate discussion; please let's not start it here.)
![](https://secure.gravatar.com/avatar/1327ce755b24b956995d68accae3eab2.jpg?s=120&d=mm&r=g)
On Mon, Apr 28, 2008 at 4:50 PM, <glyph@divmod.com> wrote:
I'm glad I could help and I'm glad that this is being worked on. Although I'm happy to leave the decision in your hands, there are a couple of things I'd like to comment on (disagree with). Also, I'd be happy to start the work of collating policy.
I dislike this. I think that deprecations should be release-based and that we should commit to time-based releases. I think this is simpler for users and for developers. This complaint would be largely solved by automation.
Presumably the timer starts at a release and only increments at a release? So, for example: T - 1 month: deprecate feature in trunk T: Release N T + 7 months: Release N+1 T + 14 months: Release N+2, feature removed. Is this understanding correct? (The fact that I need to ask is largely why I don't like "both time & release based".)
I think the data on this is skewed, since there was about a 1.4 year gap between the last 2 releases of Twisted. If we released each month, I can imagine this would change. Nevertheless, I'm content with this sort of time frame for now, as long as the support for it is well automated.
I think that this is a nice feature, but not worth breaking our backs over. (It might be really easy to do though).
I disagree very strongly on this detail. The deprecation API should be higher level than that. Specifically, even we implement it with the warnings system, I don't think we should litter that decision all over our code base.
I think this is wasted effort. Let's just build the damn tool.
What about code currently marked as deprecated?
Me. I wouldn't have raised the issue if I wasn't willing. jml
![](https://secure.gravatar.com/avatar/1327ce755b24b956995d68accae3eab2.jpg?s=120&d=mm&r=g)
On Mon, Apr 28, 2008 at 5:36 PM, Jonathan Lange <jml@mumak.net> wrote:
That said, I would be greatly surprised if you guys *didn't* have opinions about implementation beyond what Glyph has already mentioned. If you have opinions, either mention them now or out-volunteer me, so I don't end up wasting my time. jml
![](https://secure.gravatar.com/avatar/d7875f8cfd8ba9262bfff2bf6f6f9b35.jpg?s=120&d=mm&r=g)
Of course! This wasn't meant to be a dictate.
The hope is that this will be the effective end result. But our release process is not *yet* (though it is the goal) completely automated, so having fall back position of minimum time is handy. Also, what happens if we decide to switch to more (or less frequent releases)?
I think so.
At ITA we've been using 2.4 for quite a while... though someone recently switched us to 2.5.
I agree. We actually talked about high level API at the meeting, possibly glyph forgot, disagrees, or just took inaccurate notes :)
![](https://secure.gravatar.com/avatar/52cff2b66b9e291797f15f0c1b3491b8.jpg?s=120&d=mm&r=g)
On 2008.04.18 15:06:10 +1000, Jonathan Lange wrote:
As a user, I don't see much difference between a PendingDeprecationWarning and a DeprecationWarning. Or between a DeprecationError and the code being removed. Simple is good.
Now, here's what I think.
* Release-based, not time-based.
Now that version numbers are based on the year, there's not a big difference. For example, if you wanted to guarantee at least a year of DeprecationWarning before removing a feature, you could implement that by saying that if the warning goes in in 8.x, then the feature can come out in 10.0. Or vice-versa. -- David Ripton dripton@ripton.net
![](https://secure.gravatar.com/avatar/869963bdf99b541c9f0bbfb04b0320f1.jpg?s=120&d=mm&r=g)
* David Ripton <dripton@ripton.net> [2008-04-18 06:13:13 -0700]:
A PendingDeprecationWarning is not visible by default, so users of an application won't be inundated with DeprecationWarning messages they can do nothing about; but a developer can turn them on in order to check if his application is using any deprecated APIs. -- mithrandi, i Ainil en-Balandor, a faer Ambar
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
On 18 Apr, 05:06 am, jml@mumak.net wrote:
Sorry for the delay. Due to a miscommunication, I thought that Chris would be the one writing up our meeting notes and announcing this. After I realized I was the one who was supposed to be doing it, I wanted to write up something official-sounding on the wiki first, but of course, there's never enough time. So here's a rough cut at the policy that we (the current "TSF board", such as it is: chris, me, JP, and itamar) agreed on at the sprint in Cambridge. Thanks, Jonathan, for motivating this; we've needed a clear statement for a long time. Someone (and this will probably be me) needs to make a complete and unambiguous index of official Twisted policy and put it together somewhere, probably on the wiki, at least at first.
I think these are all the questions we need to answer:
The proposed policy does break down as a list of answers to these questions, so one point at a time:
- Is it time-based or release-based?
Both. There will be a minimum amount of time and a minimum number of releases before a deprecated feature may be removed.
- How long for?
Every deprecation must last for a minimum of 2 releases and a minimum of one year. Of course, anyone who wants to keep maintaining deprecated APIs for longer than that may do so. I know this is somewhat longer than you've suggested, but at the meeting we ran down a laundry list of real-world usages of Twisted and pretty much nobody upgrades Twisted more than once per year. In fact, once per 2 years seems to be the average, and that's a fairly ambitious estimate. The objective of providing a year-long deprecation period is to allow a user who is performing their bi-yearly Twisted upgrade to do so with no more than 2 intermediary upgrades.
- Do we grade deprecations? How?
There will be three phases of deprecation. When a deprecation is first introduced (in trunk) the "deprecation counter" will be at 3. When that deprecation sees its first release, it decrements to 2. Deprecations at levels 3 and 2 will be PendingDeprecationWarning. When that same deprecation sees its second release after a 6-month period, the counter decrements to 1, and finally, after a second 6-month period, it decrements to 0 and can be removed. Deprecations with a counter at 1 and at 0 (if they still exist) should emit a DeprecationWarning. The counter may not move down past 2 until *all instances of the emitted warning* have been removed from the Twisted test suite, with the exception of tests specifically for the deprecated functionality itself (i.e. tests that call assertWarns). The reason that this is described as a counter rather than primarily in terms of (Pending)DeprecationWarning is that this was a subject of intense debate during the meeting. There is definitely a consensus that the Python warnings system is not a sufficient tool we have to deal with the kind of notifications that we want to provide. There is also a consensus that it is the only tool available. So, let me provide some more detail on the desired behavior here. The idea behind using PendingDeprecationWarning is that *users* of a piece of software which depends on Twisted should, in principle, be able to upgrade Twisted by one version without seeing any error output. However, *maintainers* of that software should immediately see all the warnings when they test with a new release. Trial should change to show all PendingDeprecationWarnings by default. However, this might be impractical due to other uses of PendingDeprecationWarning - if that is the case, Twisted should include its own warning class. It may be helpful to do that in order to include the additional metadata required for an automated deprecation workflow, however. The desired deprecation workflow is: * Twisted developer deprecates functionality, by adding a warnings.warn(TwistedDeprecationWarning(some useful metadata)) to the code. * The release process automatically runs "update-deprecations" over the codebase, updating the deprecation counters in the developer-supplied metadata appropriately. The release goes out. (Ideally this would be done without actually having to modify the whole codebase, updating a central deprecation / release index.) * Another release happens that sets some counters to zero. * A developer drops support for some deprecated functionality, confident in their ability to do so by observing the zero (or negative) value for the counter. An obvious remaining piece of work to implement this final policy is to define some temporary manual things that we can do until such a tool is implemented, and implement the tool itself as soon as possible. I don't believe any tickets have yet been filed for this, and *that* I am leaving in our venerable release manager's court, since this is all a part of the release process except for the fairly minor change to trial. However, in the absence of any tools, this policy does apply now, it will just be a bit of a pain to work out where the counter stands on any particular deprecation until we've got some more metadata to help us.
- Which code is subject to this policy?
All Python code released in Twisted, with the exceptions of private modules and test modules. Only code which has been present in a release needs to be deprecated. Anything which was added after the last release and has not yet been present in any other release may be modified at will. (We try to keep trunk stable, but this only applies to code that was relying on features in previous releases.) I think that CompatibilityPolicy's explanation of an "incompatible change" explains this. Users: do not import anything from a package named "test", or any name (module, class, or function) which begins with "_"; bears will eat you. This code may change at any time. (Not a part of the policy: I personally want to add some caveats here, where users of Twisted can ask for a grace period on private APIs that people actually needed to use, but I think for now let's err on the side of allowing the deprecation - I don't want to encourage people to use private APIs. Users: if you find that there are things you can't do with the public APIs and you really need a grace period to upgrade your applications, please speak up. Eventually, I'd like to have a very aggressive "you can't even import (or invoke) this if it's private" regime where users can't accidentally use private functionality without first seeing a runtime error of some kind that they have to explicitly silence, as with my "pyexport" hack. Once we've done *that* we should definitely have a zero-tolerance policy on supporting private stuff, though...) There's obviously some work to do here to make this policy easy and convenient to follow. This needs to be edited, CompatibilityPolicy updated, and prominently linked. We need someone to write up at least two different summaries: one for maintainers of projects using Twisted ("What kind of compatibility should I expect from Twisted releases?") one for Twisted contributors ("How do I add a deprecation? When can I remove it?") and maybe one for users and one for packagers, too. We need some tools to help us update deprecations. We need trial to change so that developers are notified earlier than their users. Do I hear any volunteers...? :)
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
On 06:50 am, glyph@divmod.com wrote:
All Python code released in Twisted, with the exceptions of private modules and test modules.
To be specific, this means code actually present in the Twisted release, which does not, for example, include web2. I guess that's still be an exception. So this doesn't just mean "everything in the repository". (Maybe we should do a release of web2 and just admit people are actually using it. But that's a totally separate discussion; please let's not start it here.)
![](https://secure.gravatar.com/avatar/1327ce755b24b956995d68accae3eab2.jpg?s=120&d=mm&r=g)
On Mon, Apr 28, 2008 at 4:50 PM, <glyph@divmod.com> wrote:
I'm glad I could help and I'm glad that this is being worked on. Although I'm happy to leave the decision in your hands, there are a couple of things I'd like to comment on (disagree with). Also, I'd be happy to start the work of collating policy.
I dislike this. I think that deprecations should be release-based and that we should commit to time-based releases. I think this is simpler for users and for developers. This complaint would be largely solved by automation.
Presumably the timer starts at a release and only increments at a release? So, for example: T - 1 month: deprecate feature in trunk T: Release N T + 7 months: Release N+1 T + 14 months: Release N+2, feature removed. Is this understanding correct? (The fact that I need to ask is largely why I don't like "both time & release based".)
I think the data on this is skewed, since there was about a 1.4 year gap between the last 2 releases of Twisted. If we released each month, I can imagine this would change. Nevertheless, I'm content with this sort of time frame for now, as long as the support for it is well automated.
I think that this is a nice feature, but not worth breaking our backs over. (It might be really easy to do though).
I disagree very strongly on this detail. The deprecation API should be higher level than that. Specifically, even we implement it with the warnings system, I don't think we should litter that decision all over our code base.
I think this is wasted effort. Let's just build the damn tool.
What about code currently marked as deprecated?
Me. I wouldn't have raised the issue if I wasn't willing. jml
![](https://secure.gravatar.com/avatar/1327ce755b24b956995d68accae3eab2.jpg?s=120&d=mm&r=g)
On Mon, Apr 28, 2008 at 5:36 PM, Jonathan Lange <jml@mumak.net> wrote:
That said, I would be greatly surprised if you guys *didn't* have opinions about implementation beyond what Glyph has already mentioned. If you have opinions, either mention them now or out-volunteer me, so I don't end up wasting my time. jml
![](https://secure.gravatar.com/avatar/d7875f8cfd8ba9262bfff2bf6f6f9b35.jpg?s=120&d=mm&r=g)
Of course! This wasn't meant to be a dictate.
The hope is that this will be the effective end result. But our release process is not *yet* (though it is the goal) completely automated, so having fall back position of minimum time is handy. Also, what happens if we decide to switch to more (or less frequent releases)?
I think so.
At ITA we've been using 2.4 for quite a while... though someone recently switched us to 2.5.
I agree. We actually talked about high level API at the meeting, possibly glyph forgot, disagrees, or just took inaccurate notes :)
participants (5)
-
David Ripton
-
glyph@divmod.com
-
Itamar Shtull-Trauring
-
Jonathan Lange
-
Tristan Seligmann