def test_should_warning_about_incompatible_plugins(self): class AirflowDeprecatedAdminViewsPlugin(AirflowPlugin): name = "test_admin_views_plugin" admin_views = [mock.MagicMock()] class AirflowDeprecatedAdminMenuLinksPlugin(AirflowPlugin): name = "test_menu_links_plugin" menu_links = [mock.MagicMock()] from airflow import plugins_manager plugins_manager.plugins = [ AirflowDeprecatedAdminViewsPlugin(), AirflowDeprecatedAdminMenuLinksPlugin() ] with self.assertLogs(plugins_manager.log) as cm: plugins_manager.initialize_web_ui_plugins() self.assertEqual(cm.output, [ 'WARNING:airflow.plugins_manager:Plugin \'test_admin_views_plugin\' may not be ' 'compatible with the current Airflow version. Please contact the author of ' 'the plugin.', 'WARNING:airflow.plugins_manager:Plugin \'test_menu_links_plugin\' may not be ' 'compatible with the current Airflow version. Please contact the author of ' 'the plugin.' ])
def init_plugins(app): """Integrate Flask and FAB with plugins""" from airflow import plugins_manager plugins_manager.initialize_web_ui_plugins() appbuilder = app.appbuilder for view in plugins_manager.flask_appbuilder_views: log.debug("Adding view %s", view["name"]) appbuilder.add_view(view["view"], view["name"], category=view["category"]) for menu_link in sorted(plugins_manager.flask_appbuilder_menu_links, key=lambda x: x["name"]): log.debug("Adding menu link %s", menu_link["name"]) appbuilder.add_link( menu_link["name"], href=menu_link["href"], category=menu_link["category"], category_icon=menu_link["category_icon"], ) for blue_print in plugins_manager.flask_blueprints: log.debug("Adding blueprint %s:%s", blue_print["name"], blue_print["blueprint"].import_name) app.register_blueprint(blue_print["blueprint"])
def dump_plugins(args): """Dump plugins information""" plugins_manager.log.setLevel(logging.DEBUG) plugins_manager.ensure_plugins_loaded() plugins_manager.integrate_dag_plugins() plugins_manager.integrate_executor_plugins() plugins_manager.initialize_extra_operators_links_plugins() plugins_manager.initialize_web_ui_plugins() _header("PLUGINS MANGER:", "#") for attr_name in PLUGINS_MANAGER_ATTRIBUTES_TO_DUMP: attr_value = getattr(plugins_manager, attr_name) print(f"{attr_name} = ", end='') pprint(attr_value) print() _header("PLUGINS:", "#") if not plugins_manager.plugins: print("No plugins loaded") else: print(f"Loaded {len(plugins_manager.plugins)} plugins") for plugin_no, plugin in enumerate(plugins_manager.plugins, 1): _header(f"{plugin_no}. {plugin.name}", "=") for attr_name in PLUGINS_ATTRIBUTES_TO_DUMP: attr_value = getattr(plugin, attr_name) print(f"{attr_name} = ", end='') pprint(attr_value) print()
def test_should_warning_about_incompatible_plugins(self, caplog): class AirflowAdminViewsPlugin(AirflowPlugin): name = "test_admin_views_plugin" admin_views = [mock.MagicMock()] class AirflowAdminMenuLinksPlugin(AirflowPlugin): name = "test_menu_links_plugin" menu_links = [mock.MagicMock()] with mock_plugin_manager(plugins=[ AirflowAdminViewsPlugin(), AirflowAdminMenuLinksPlugin() ]), caplog.at_level(logging.WARNING, logger='airflow.plugins_manager'): from airflow import plugins_manager plugins_manager.initialize_web_ui_plugins() assert caplog.record_tuples == [ ( "airflow.plugins_manager", logging.WARNING, "Plugin 'test_admin_views_plugin' may not be compatible with the current Airflow version. " "Please contact the author of the plugin.", ), ( "airflow.plugins_manager", logging.WARNING, "Plugin 'test_menu_links_plugin' may not be compatible with the current Airflow version. " "Please contact the author of the plugin.", ), ]
def init_plugins(app): """Integrate Flask and FAB with plugins""" from airflow import plugins_manager plugins_manager.initialize_web_ui_plugins() appbuilder = app.appbuilder for view in plugins_manager.flask_appbuilder_views: name = view.get('name') if name: log.debug("Adding view %s with menu", name) appbuilder.add_view(view["view"], name, category=view["category"]) else: # if 'name' key is missing, intent is to add view without menu log.debug("Adding view %s without menu", str(type(view["view"]))) appbuilder.add_view_no_menu(view["view"]) for menu_link in sorted(plugins_manager.flask_appbuilder_menu_links, key=lambda x: x["name"]): log.debug("Adding menu link %s", menu_link["name"]) appbuilder.add_link( menu_link["name"], href=menu_link["href"], category=menu_link["category"], category_icon=menu_link["category_icon"], ) for blue_print in plugins_manager.flask_blueprints: log.debug("Adding blueprint %s:%s", blue_print["name"], blue_print["blueprint"].import_name) app.register_blueprint(blue_print["blueprint"])
def dump_plugins(args): """Dump plugins information""" plugins_manager.ensure_plugins_loaded() plugins_manager.integrate_macros_plugins() plugins_manager.integrate_executor_plugins() plugins_manager.initialize_extra_operators_links_plugins() plugins_manager.initialize_web_ui_plugins() if not plugins_manager.plugins: print("No plugins loaded") return plugins_info: List[Dict[str, str]] = [] for plugin in plugins_manager.plugins: info = {"name": plugin.name} info.update( {n: getattr(plugin, n) for n in PLUGINS_ATTRIBUTES_TO_DUMP}) plugins_info.append(info) # Remove empty info if args.output == "table": # pylint: disable=too-many-nested-blocks # We can do plugins_info[0] as the element it will exist as there's # at least one plugin at this point for col in list(plugins_info[0]): if all(not bool(p[col]) for p in plugins_info): for plugin in plugins_info: del plugin[col] AirflowConsole().print_as(plugins_info, output=args.output)
def test_should_not_warning_about_fab_plugins(self): class AirflowAdminViewsPlugin(AirflowPlugin): name = "test_admin_views_plugin" appbuilder_views = [mock.MagicMock()] class AirflowAdminMenuLinksPlugin(AirflowPlugin): name = "test_menu_links_plugin" appbuilder_menu_items = [mock.MagicMock()] with mock_plugin_manager(plugins=[AirflowAdminViewsPlugin(), AirflowAdminMenuLinksPlugin()]): from airflow import plugins_manager # assert not logs with self.assertRaises(AssertionError), self.assertLogs(plugins_manager.log): plugins_manager.initialize_web_ui_plugins()
def integrate_plugins(): """Integrate plugins to the context""" from airflow import plugins_manager plugins_manager.initialize_web_ui_plugins() for v in plugins_manager.flask_appbuilder_views: log.debug("Adding view %s", v["name"]) appbuilder.add_view(v["view"], v["name"], category=v["category"]) for ml in sorted(plugins_manager.flask_appbuilder_menu_links, key=lambda x: x["name"]): log.debug("Adding menu link %s", ml["name"]) appbuilder.add_link(ml["name"], href=ml["href"], category=ml["category"], category_icon=ml["category_icon"])
def test_should_not_warning_about_fab_plugins(self, caplog): class AirflowAdminViewsPlugin(AirflowPlugin): name = "test_admin_views_plugin" appbuilder_views = [mock.MagicMock()] class AirflowAdminMenuLinksPlugin(AirflowPlugin): name = "test_menu_links_plugin" appbuilder_menu_items = [mock.MagicMock()] with mock_plugin_manager( plugins=[AirflowAdminViewsPlugin(), AirflowAdminMenuLinksPlugin()] ), caplog.at_level(logging.WARNING, logger='airflow.plugins_manager'): from airflow import plugins_manager plugins_manager.initialize_web_ui_plugins() assert caplog.record_tuples == []
def dump_plugins(args): """Dump plugins information""" plugins_manager.ensure_plugins_loaded() plugins_manager.integrate_macros_plugins() plugins_manager.integrate_executor_plugins() plugins_manager.initialize_extra_operators_links_plugins() plugins_manager.initialize_web_ui_plugins() if not plugins_manager.plugins: print("No plugins loaded") return console = Console() console.print("[bold yellow]SUMMARY:[/bold yellow]") console.print( f"[bold green]Plugins directory[/bold green]: {conf.get('core', 'plugins_folder')}\n", highlight=False) console.print( f"[bold green]Loaded plugins[/bold green]: {len(plugins_manager.plugins)}\n", highlight=False) for attr_name in PLUGINS_MANAGER_ATTRIBUTES_TO_DUMP: attr_value: Optional[List[Any]] = getattr(plugins_manager, attr_name) if not attr_value: continue table = SimpleTable(title=attr_name.capitalize().replace("_", " ")) table.add_column(width=100) for item in attr_value: # pylint: disable=not-an-iterable table.add_row(f"- {_get_name(item)}", ) console.print(table) console.print("[bold yellow]DETAILED INFO:[/bold yellow]") for plugin in plugins_manager.plugins: table = SimpleTable(title=plugin.name) for attr_name in PLUGINS_ATTRIBUTES_TO_DUMP: value = getattr(plugin, attr_name) if not value: continue table.add_row(attr_name.capitalize().replace("_", " "), _join_plugins_names(value)) console.print(table)