[Tres Seaver -- I think; I'm missing context for this email]
Note that I have just figured out that we can make DeprecationWarnings more useful by passing the 'stacklevel' argument to 'warnings.warn'; passing a value of 2 for that argument causes the warning to be reported against the *caller* of the code issuing the warning, which makes it possible to find and remove the deprecated use.
I can recommend the approach I use in ZODB. There's a utility module in ZODB, containing (among other things) functions like this one: """ # Raise DeprecationWarning, noting that the deprecated thing will go # away in ZODB 3.6. Point to the caller of our caller (i.e., at the # code using the deprecated thing). def deprecated36(msg): warnings.warn("This will be removed in ZODB 3.6:\n%s" % msg, DeprecationWarning, stacklevel=3) """ So every gimmick that's going to go away in ZODB 3.6 imports `deprecated36` from the utility module, and calls it with an appropriate message. As an intended bonus, when I release ZODB 3.6 I can just grep for "deprecated36" to _find_ the code that's supposed to go away (I also annotate tests and docs that should go away with "deprecated36"). Using a common function also ensures that every deprecation warning starts with the same string (identifying the release in which the thing will go away). Note: sometimes _internals_ use deprecated gimmicks in order to support deprecated gimmicks too, and then stacklevel=3 is too small. It's happened so rarely in ZODB that I haven't tried to "do something" about that yet.