stale[bot] closed pull request #2228: [AIRFLOW-351] Ensure python_callable is 
pickleable
URL: https://github.com/apache/incubator-airflow/pull/2228
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/airflow/operators/python_operator.py 
b/airflow/operators/python_operator.py
index cf240f2802..a8febf0d74 100644
--- a/airflow/operators/python_operator.py
+++ b/airflow/operators/python_operator.py
@@ -13,8 +13,10 @@
 # limitations under the License.
 
 from builtins import str
+import copy
 from datetime import datetime
 import logging
+import pickle
 
 from airflow.exceptions import AirflowException
 from airflow.models import BaseOperator, TaskInstance
@@ -66,6 +68,10 @@ def __init__(
         super(PythonOperator, self).__init__(*args, **kwargs)
         if not callable(python_callable):
             raise AirflowException('`python_callable` param must be callable')
+        try:
+            pickle.dumps(copy.deepcopy(python_callable))
+        except TypeError:
+            raise AirflowException('`python_callable` param must be 
pickleable')
         self.python_callable = python_callable
         self.op_args = op_args or []
         self.op_kwargs = op_kwargs or {}
diff --git a/tests/operators/python_operator.py 
b/tests/operators/python_operator.py
index 3aa8b6cf8f..56053052f6 100644
--- a/tests/operators/python_operator.py
+++ b/tests/operators/python_operator.py
@@ -15,6 +15,7 @@
 from __future__ import print_function, unicode_literals
 
 import datetime
+import threading
 import unittest
 
 from airflow import configuration, DAG
@@ -33,6 +34,28 @@
 FROZEN_NOW = datetime.datetime(2016, 1, 2, 12, 1, 1)
 
 
+class NotPickleable(object):
+
+    def __init__(self):
+        # [AIRFLOW-351] This object prevents pickle, which
+        # eventually causes TypeError by running `airflow clear`
+        self.lock = threading.Lock()
+
+    def callable(self):
+        pass
+
+
+class StatefulTask(object):
+    def do_run(self):
+        self.run = True
+
+    def clear_run(self):
+        self.run = False
+
+    def is_run(self):
+        return self.run
+
+
 class PythonOperatorTest(unittest.TestCase):
 
     def setUp(self):
@@ -45,27 +68,19 @@ def setUp(self):
                 'start_date': DEFAULT_DATE},
             schedule_interval=INTERVAL)
         self.addCleanup(self.dag.clear)
-        self.clear_run()
-        self.addCleanup(self.clear_run)
-
-    def do_run(self):
-        self.run = True
-
-    def clear_run(self):
-        self.run = False
-
-    def is_run(self):
-        return self.run
+        self.stateful_task = StatefulTask()
+        self.stateful_task.clear_run()
+        self.addCleanup(self.stateful_task.clear_run)
 
     def test_python_operator_run(self):
         """Tests that the python callable is invoked on task run."""
         task = PythonOperator(
-            python_callable=self.do_run,
+            python_callable=self.stateful_task.do_run,
             task_id='python_operator',
             dag=self.dag)
-        self.assertFalse(self.is_run())
+        self.assertFalse(self.stateful_task.is_run())
         task.run(start_date=DEFAULT_DATE, end_date=DEFAULT_DATE)
-        self.assertTrue(self.is_run())
+        self.assertTrue(self.stateful_task.is_run())
 
     def test_python_operator_python_callable_is_callable(self):
         """Tests that PythonOperator will only instantiate if
@@ -83,6 +98,15 @@ def test_python_operator_python_callable_is_callable(self):
                 task_id='python_operator',
                 dag=self.dag)
 
+    def test_python_operator_python_callable_is_pickleable(self):
+        """Tests that PythonOperator will only instantiate if
+        the python_callable argument is able to pickle."""
+        with self.assertRaises(AirflowException):
+            PythonOperator(
+                python_callable=NotPickleable().callable,
+                task_id='python_operator',
+                dag=self.dag)
+
 
 class BranchOperatorTest(unittest.TestCase):
     def setUp(self):


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to