Repository: ethereum/web3.py

Issue:
Deprecation of Contract.on and Contract.pastEvents
* Version: 4.x


### What was wrong?

With the recent deprecation of the old filter API, we forgot to address `Contract.on` and `Contract.pastEvents`.  These still hold some of the old semantics and I think they would benefit from being replaced by a new API.


### How can it be fixed?

I suggest deprecating both of the old contract filter APIs in favor of a new `Contract.eventFilter` which doesn't do any implicit *magic* with the block numbers and simply creates a filter that the user can then decide how they want to interact with it.




Discussion:

Resolving patch:
diff --git a/web3/contract.py b/web3/contract.py
--- a/web3/contract.py
+++ b/web3/contract.py
@@ -51,6 +51,7 @@
 )
 from web3.utils.decorators import (
     combomethod,
+    deprecated_for,
 )
 from web3.utils.empty import (
     empty,
@@ -332,6 +333,7 @@ def encodeABI(cls, fn_name, args=None, kwargs=None, data=None):
         return cls._encode_abi(fn_abi, fn_arguments, data)
 
     @combomethod
+    @deprecated_for("an upcoming v4 method: eventFilter()")
     def on(self, event_name, filter_params=None, *callbacks):
         """
         Register a callback to be triggered on the appropriate events.
@@ -367,6 +369,7 @@ def on(self, event_name, filter_params=None, *callbacks):
         return log_filter
 
     @combomethod
+    @deprecated_for("an upcoming v4 method: eventFilter()")
     def pastEvents(self, event_name, filter_params=None, *callbacks):
         """
         Register a callback to be triggered on all past events.
diff --git a/web3/utils/filters.py b/web3/utils/filters.py
--- a/web3/utils/filters.py
+++ b/web3/utils/filters.py
@@ -1,5 +1,6 @@
 import re
 import random
+import warnings
 
 from eth_utils import (
     is_string,
@@ -93,6 +94,15 @@ def _run(self):
             else:
                 sleep(self.poll_interval)
 
+    def _warn_async_deprecated(self, method_name):
+        warnings.warn(DeprecationWarning(
+            "Asynchronous filters have been deprecated "
+            "and `{0}` will be removed from the Filter class "
+            "in future releases.  Prepare to update your code to work "
+            "synchronously or handle asynchrony explicitly with a "
+            "third party library, when switching to web3 version 4.".format(method_name)
+        ))
+
     def format_entry(self, entry):
         """
         Hook for subclasses to change the format of the value that is passed
@@ -107,6 +117,8 @@ def is_valid_entry(self, entry):
         return True
 
     def watch(self, *callbacks):
+        self._warn_async_deprecated("watch")
+
         if self.stopped:
             raise ValueError("Cannot watch on a filter that has been stopped")
         self.callbacks.extend(callbacks)
@@ -116,6 +128,8 @@ def watch(self, *callbacks):
         sleep(0)
 
     def stop_watching(self, timeout=0):
+        self._warn_async_deprecated("stop_watching")
+
         self.running = False
         self.stopped = True
         self.web3.eth.uninstallFilter(self.filter_id)
@@ -163,6 +177,13 @@ def __init__(self, *args, **kwargs):
         super(LogFilter, self).__init__(*args, **kwargs)
 
     def get(self, only_changes=True):
+        warnings.warn(DeprecationWarning(
+            "LogFilter.get has been deprecated and "
+            "will be removed from the LogFilter class in future releases. "
+            "Update your code to use the new methods: "
+            "LogFilter.get_new_entries and LogFilter.get_all_entries."
+        ))
+
         if self.running:
             raise ValueError(
                 "Cannot call `get` on a filter object which is actively watching"
@@ -234,6 +255,8 @@ def _run(self):
                 sleep(self.poll_interval)
 
     def stop_watching(self, timeout=0):
+        self._warn_async_deprecated("stop_watching")
+
         self.running = False
         self.stopped = True
         self.web3.shh.uninstallFilter(self.filter_id)


Test patch: