Repository: HypothesisWorks/hypothesis

Issue:
Add "since=" argument to note_deprecation
~~[The "sleep constructor"](https://twitter.com/johnregehr/status/920691341738123264) is a highly effective way to stop people using an interface without actually breaking compatibility: when the deprecated function is called, you emit a warning and then sleep for a few seconds before doing the thing.  I think we should do this, and automatically increase the sleep period over time.~~  This would be fun but probably not helpful, so we're just going to track the dates for internal use.

I originally suggested this for v4 in #1696, but (a) why wait? and (b), why make that diff any larger than it needs to be?

- [x] Add a `since=` argument to `note_deprecation`, which takes a date in `"YYYY-MM-DD"` format.
- [x] Add the real date of deprecation to all calls and make `since` a required argument.
- [ ] Set up our CI release function (in `tooling/`) to replace `since="RELEASEDAY"` with the then-current date string so that we get it right automatically.  
- [ ] Ensure that `note_deprecation` does the same substitution at runtime to support testing unmerged PRs, then validate that the string is a valid date after 2016 (our current oldest deprecation)


Discussion:
I'm not actually wild about the sleep incentive idea. It's tempting but I think it will burn more goodwill than it will achieve useful results.
Why is the funnest stuff always a bad idea? Ah well...

Just the CI bit to insert the appropriate date then, and an assertion that the since argument is a valid date or the releaseday string. 
> Why is the funnest stuff always a bad idea? Ah well...

[![image](https://user-images.githubusercontent.com/28623/50234580-eb18b000-03ad-11e9-9169-1961f49beb47.png)](http://www.girlgeniusonline.com/comic.php?date=20031017)
I agree, that this sleep-constructor idea is funny, but not good. People could easily avoid sleeping release and remain with the old one, because hypothesis just works. 

Another issues will be caused for public CI services. Are we sure that such sleeping tests will fail with proper error when CI will abort them because of execution timeout? Hypothesis tests are tend to run longer. Such change may let them run even more longer.

I think it would be more than enough a friendly (stdlib) warning and follow well known semantic versioning (may be not stricly, but with the similar expectations) when all the deprecated things turns into pumpkit with the next major release.

Resolving patch:
diff --git a/hypothesis-python/src/hypothesis/_settings.py b/hypothesis-python/src/hypothesis/_settings.py
--- a/hypothesis-python/src/hypothesis/_settings.py
+++ b/hypothesis-python/src/hypothesis/_settings.py
@@ -24,6 +24,7 @@
 from __future__ import absolute_import, division, print_function
 
 import contextlib
+import datetime
 import inspect
 import os
 import threading
@@ -929,6 +930,9 @@ def note_deprecation(message, since, verbosity=None):
     if verbosity is None:
         verbosity = settings.default.verbosity
     assert verbosity is not None
+    if since != "RELEASEDAY":
+        date = datetime.datetime.strptime(since, "%Y-%m-%d").date()
+        assert datetime.date(2016, 1, 1) <= date
     warning = HypothesisDeprecationWarning(message)
     if verbosity > Verbosity.quiet:
         warnings.warn(warning, stacklevel=2)
diff --git a/tooling/src/hypothesistooling/projects/hypothesispython.py b/tooling/src/hypothesistooling/projects/hypothesispython.py
--- a/tooling/src/hypothesistooling/projects/hypothesispython.py
+++ b/tooling/src/hypothesistooling/projects/hypothesispython.py
@@ -121,6 +121,18 @@ def update_changelog_and_version():
     with open(CHANGELOG_FILE, "w") as o:
         o.write("\n".join(new_changelog_parts))
 
+    # Replace the `since="RELEASEDAY"` argument to `note_deprecation`
+    # with today's date, to record it for future reference.
+    before = 'since="RELEASEDAY"'
+    after = before.replace("RELEASEDAY", rm.release_date_string())
+    for root, _, files in os.walk(PYTHON_SRC):
+        for fname in (os.path.join(root, f) for f in files if f.endswith(".py")):
+            with open(fname) as f:
+                contents = f.read()
+            if before in contents:
+                with open(fname, "w") as f:
+                    f.write(contents.replace(before, after))
+
 
 CHANGELOG_FILE = os.path.join(HYPOTHESIS_PYTHON, "docs", "changes.rst")
 DIST = os.path.join(HYPOTHESIS_PYTHON, "dist")


Test patch: