Coverage for /pythoncovmergedfiles/medio/medio/src/airflow/airflow/hooks/base.py: 65%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

49 statements  

1# 

2# Licensed to the Apache Software Foundation (ASF) under one 

3# or more contributor license agreements. See the NOTICE file 

4# distributed with this work for additional information 

5# regarding copyright ownership. The ASF licenses this file 

6# to you under the Apache License, Version 2.0 (the 

7# "License"); you may not use this file except in compliance 

8# with the License. You may obtain a copy of the License at 

9# 

10# http://www.apache.org/licenses/LICENSE-2.0 

11# 

12# Unless required by applicable law or agreed to in writing, 

13# software distributed under the License is distributed on an 

14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 

15# KIND, either express or implied. See the License for the 

16# specific language governing permissions and limitations 

17# under the License. 

18"""Base class for all hooks.""" 

19 

20from __future__ import annotations 

21 

22import logging 

23import warnings 

24from typing import TYPE_CHECKING, Any 

25 

26from airflow.exceptions import RemovedInAirflow3Warning 

27from airflow.typing_compat import Protocol 

28from airflow.utils.log.logging_mixin import LoggingMixin 

29 

30if TYPE_CHECKING: 

31 from airflow.models.connection import Connection # Avoid circular imports. 

32 

33log = logging.getLogger(__name__) 

34 

35 

36class BaseHook(LoggingMixin): 

37 """ 

38 Abstract base class for hooks. 

39 

40 Hooks are meant as an interface to 

41 interact with external systems. MySqlHook, HiveHook, PigHook return 

42 object that can handle the connection and interaction to specific 

43 instances of these systems, and expose consistent methods to interact 

44 with them. 

45 

46 :param logger_name: Name of the logger used by the Hook to emit logs. 

47 If set to `None` (default), the logger name will fall back to 

48 `airflow.task.hooks.{class.__module__}.{class.__name__}` (e.g. DbApiHook will have 

49 *airflow.task.hooks.airflow.providers.common.sql.hooks.sql.DbApiHook* as logger). 

50 """ 

51 

52 def __init__(self, logger_name: str | None = None): 

53 super().__init__() 

54 self._log_config_logger_name = "airflow.task.hooks" 

55 self._logger_name = logger_name 

56 

57 @classmethod 

58 def get_connections(cls, conn_id: str) -> list[Connection]: 

59 """ 

60 Get all connections as an iterable, given the connection id. 

61 

62 :param conn_id: connection id 

63 :return: array of connections 

64 """ 

65 warnings.warn( 

66 "`BaseHook.get_connections` method will be deprecated in the future." 

67 "Please use `BaseHook.get_connection` instead.", 

68 RemovedInAirflow3Warning, 

69 stacklevel=2, 

70 ) 

71 return [cls.get_connection(conn_id)] 

72 

73 @classmethod 

74 def get_connection(cls, conn_id: str) -> Connection: 

75 """ 

76 Get connection, given connection id. 

77 

78 :param conn_id: connection id 

79 :return: connection 

80 """ 

81 from airflow.models.connection import Connection 

82 

83 conn = Connection.get_connection_from_secrets(conn_id) 

84 log.info("Using connection ID '%s' for task execution.", conn.conn_id) 

85 return conn 

86 

87 @classmethod 

88 def get_hook(cls, conn_id: str) -> BaseHook: 

89 """ 

90 Return default hook for this connection id. 

91 

92 :param conn_id: connection id 

93 :return: default hook for this connection 

94 """ 

95 connection = cls.get_connection(conn_id) 

96 return connection.get_hook() 

97 

98 def get_conn(self) -> Any: 

99 """Return connection for the hook.""" 

100 raise NotImplementedError() 

101 

102 @classmethod 

103 def get_connection_form_widgets(cls) -> dict[str, Any]: 

104 return {} 

105 

106 @classmethod 

107 def get_ui_field_behaviour(cls) -> dict[str, Any]: 

108 return {} 

109 

110 

111class DiscoverableHook(Protocol): 

112 """ 

113 Interface that providers *can* implement to be discovered by ProvidersManager. 

114 

115 It is not used by any of the Hooks, but simply methods and class fields described here are 

116 implemented by those Hooks. Each method is optional -- only implement the ones you need. 

117 

118 The conn_name_attr, default_conn_name, conn_type should be implemented by those 

119 Hooks that want to be automatically mapped from the connection_type -> Hook when get_hook method 

120 is called with connection_type. 

121 

122 Additionally hook_name should be set when you want the hook to have a custom name in the UI selection 

123 Name. If not specified, conn_name will be used. 

124 

125 The "get_ui_field_behaviour" and "get_connection_form_widgets" are optional - override them if you want 

126 to customize the Connection Form screen. You can add extra widgets to parse your extra fields via the 

127 get_connection_form_widgets method as well as hide or relabel the fields or pre-fill 

128 them with placeholders via get_ui_field_behaviour method. 

129 

130 Note that the "get_ui_field_behaviour" and "get_connection_form_widgets" need to be set by each class 

131 in the class hierarchy in order to apply widget customizations. 

132 

133 For example, even if you want to use the fields from your parent class, you must explicitly 

134 have a method on *your* class: 

135 

136 .. code-block:: python 

137 

138 @classmethod 

139 def get_ui_field_behaviour(cls): 

140 return super().get_ui_field_behaviour() 

141 

142 You also need to add the Hook class name to list 'hook_class_names' in provider.yaml in case you 

143 build an internal provider or to return it in dictionary returned by provider_info entrypoint in the 

144 package you prepare. 

145 

146 You can see some examples in airflow/providers/jdbc/hooks/jdbc.py. 

147 

148 """ 

149 

150 conn_name_attr: str 

151 default_conn_name: str 

152 conn_type: str 

153 hook_name: str 

154 

155 @staticmethod 

156 def get_connection_form_widgets() -> dict[str, Any]: 

157 """ 

158 Return dictionary of widgets to be added for the hook to handle extra values. 

159 

160 If you have class hierarchy, usually the widgets needed by your class are already 

161 added by the base class, so there is no need to implement this method. It might 

162 actually result in warning in the logs if you try to add widgets that have already 

163 been added by the base class. 

164 

165 Note that values of Dict should be of wtforms.Field type. It's not added here 

166 for the efficiency of imports. 

167 

168 """ 

169 ... 

170 

171 @staticmethod 

172 def get_ui_field_behaviour() -> dict[str, Any]: 

173 """ 

174 Attributes of the UI field. 

175 

176 Returns dictionary describing customizations to implement in javascript handling the 

177 connection form. Should be compliant with airflow/customized_form_field_behaviours.schema.json' 

178 

179 

180 If you change conn_type in a derived class, you should also 

181 implement this method and return field customizations appropriate to your Hook. This 

182 is because the child hook will have usually different conn_type and the customizations 

183 are per connection type. 

184 

185 .. seealso:: 

186 :class:`~airflow.providers.google.cloud.hooks.compute_ssh.ComputeSSH` as an example 

187 

188 """ 

189 ...