You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ka...@apache.org on 2020/11/07 20:18:17 UTC

[airflow] branch v1-10-stable updated: Deprecate importing Hooks from plugin-created module (#12133)

This is an automated email from the ASF dual-hosted git repository.

kaxilnaik pushed a commit to branch v1-10-stable
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v1-10-stable by this push:
     new 321bf6b  Deprecate importing Hooks from plugin-created module (#12133)
321bf6b is described below

commit 321bf6ba0d776a34468831342c615f838d97c28d
Author: Ash Berlin-Taylor <as...@firemirror.com>
AuthorDate: Sat Nov 7 20:17:25 2020 +0000

    Deprecate importing Hooks from plugin-created module (#12133)
    
    Closes #9506
---
 airflow/hooks/__init__.py                 |  6 ++++++
 airflow/plugins_manager.py                | 18 +++++++++++-------
 tests/plugins/test_plugins_manager_www.py | 30 +++++++++++++++++++++++++-----
 3 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/airflow/hooks/__init__.py b/airflow/hooks/__init__.py
index 1f1c40f..745edf8 100644
--- a/airflow/hooks/__init__.py
+++ b/airflow/hooks/__init__.py
@@ -22,6 +22,8 @@ import os as _os
 import sys
 
 
+PY37 = sys.version_info >= (3, 7)
+
 # ------------------------------------------------------------------------
 #
 # #TODO #FIXME Airflow 2.0
@@ -77,6 +79,10 @@ def _integrate_plugins():
     from airflow.plugins_manager import hooks_modules
     for hooks_module in hooks_modules:
         sys.modules[hooks_module.__name__] = hooks_module
+
+        if not PY37:
+            from pep562 import Pep562
+            hooks_module = Pep562(hooks_module.__name__)
         globals()[hooks_module._name] = hooks_module
 
         ##########################################################
diff --git a/airflow/plugins_manager.py b/airflow/plugins_manager.py
index 5b86fd1..80099b2 100644
--- a/airflow/plugins_manager.py
+++ b/airflow/plugins_manager.py
@@ -209,10 +209,12 @@ plugins = load_entrypoint_plugins(
 )
 
 
-def make_deprecated_module(name, objects, plugin):
-    name = name.lower()
+def make_deprecated_module(kind, plugin, objects=None):
+    name = 'airflow.{}.{}'.format(kind, plugin.name)
     module = imp.new_module(name)
     module._name = name.split('.')[-1]
+    if objects is None:
+        objects = getattr(plugin, kind)
     module._objects = objects
     objects = {o.__name__: o for o in objects}
 
@@ -236,12 +238,12 @@ def make_deprecated_module(name, objects, plugin):
             correct_import_name = '.'.join((obj.__module__, obj_name))
 
         warnings.warn(
-            "Importing '{}' from under 'airflow.operators.*' has been deprecated and should be directly "
+            "Importing '{}' from under 'airflow.{}.*' has been deprecated and should be directly "
             "imported as '{}' instead.\n"
             "\n"
             "Support for importing from within the airflow namespace for plugins will be dropped entirely "
             "in Airflow 2.0. See <http://airflow.apache.org/docs/stable/howto/custom-operator.html>.".format(
-                attrname, correct_import_name
+                attrname, kind, correct_import_name
             ),
             category=FutureWarning,
             stacklevel=stacklevel
@@ -292,11 +294,13 @@ during deserialization
 
 for p in plugins:
     operators_modules.append(
-        make_deprecated_module('airflow.operators.' + p.name, p.operators + p.sensors, p))
+        make_deprecated_module('operators', p, p.operators + p.sensors))
     sensors_modules.append(
-        make_deprecated_module('airflow.sensors.' + p.name, p.sensors, p)
+        make_deprecated_module('sensors', p)
+    )
+    hooks_modules.append(
+        make_deprecated_module('hooks', p)
     )
-    hooks_modules.append(make_module('airflow.hooks.' + p.name, p.hooks))
     executors_modules.append(
         make_module('airflow.executors.' + p.name, p.executors))
     macros_modules.append(make_module('airflow.macros.' + p.name, p.macros))
diff --git a/tests/plugins/test_plugins_manager_www.py b/tests/plugins/test_plugins_manager_www.py
index dd21f65..656f8b1 100644
--- a/tests/plugins/test_plugins_manager_www.py
+++ b/tests/plugins/test_plugins_manager_www.py
@@ -22,7 +22,7 @@ from __future__ import division
 from __future__ import print_function
 from __future__ import unicode_literals
 
-import unittest
+import six
 from mock import MagicMock, PropertyMock
 
 from flask.blueprints import Blueprint
@@ -37,19 +37,39 @@ from airflow.www.app import create_app
 
 from tests.plugins.test_plugin import MockPluginA, MockPluginB, MockPluginC
 
+if six.PY2:
+    # Need `assertWarns` back-ported from unittest2
+    import unittest2 as unittest
+else:
+    import unittest
 
-class PluginsTest(unittest.TestCase):
 
+class PluginsTest(unittest.TestCase):
     def test_operators(self):
-        from airflow.operators.test_plugin import PluginOperator
+        with self.assertWarnsRegex(
+            FutureWarning, r"'PluginOperator' from under 'airflow.operators.*'"
+        ):
+            from airflow.operators.test_plugin import PluginOperator
         self.assertTrue(issubclass(PluginOperator, BaseOperator))
 
+        with self.assertWarnsRegex(
+            FutureWarning, r"'PluginSensorOperator' from under 'airflow.operators.*'"
+        ):
+            from airflow.operators.test_plugin import PluginSensorOperator
+        self.assertTrue(issubclass(PluginSensorOperator, BaseSensorOperator))
+
     def test_sensors(self):
-        from airflow.sensors.test_plugin import PluginSensorOperator
+        with self.assertWarnsRegex(
+            FutureWarning, r"'PluginSensorOperator' from under 'airflow.sensors.*'"
+        ):
+            from airflow.sensors.test_plugin import PluginSensorOperator
         self.assertTrue(issubclass(PluginSensorOperator, BaseSensorOperator))
 
     def test_hooks(self):
-        from airflow.hooks.test_plugin import PluginHook
+        with self.assertWarnsRegex(
+            FutureWarning, r"'PluginHook' from under 'airflow.hooks.*'"
+        ):
+            from airflow.hooks.test_plugin import PluginHook
         self.assertTrue(issubclass(PluginHook, BaseHook))
 
     def test_executors(self):