Conditions | 19 |
Total Lines | 181 |
Code Lines | 123 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like tabpy.tabpy_server.app.app.TabPyApp._parse_config() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | from argparse import ArgumentParser |
||
136 | def _parse_config(self, config_file): |
||
137 | """Provide consistent mechanism for pulling in configuration. |
||
138 | |||
139 | Attempt to retain backward compatibility for |
||
140 | existing implementations by grabbing port |
||
141 | setting from CLI first. |
||
142 | |||
143 | Take settings in the following order: |
||
144 | |||
145 | 1. CLI arguments if present |
||
146 | 2. config file |
||
147 | 3. OS environment variables (for ease of |
||
148 | setting defaults if not present) |
||
149 | 4. current defaults if a setting is not present in any location |
||
150 | |||
151 | Additionally provide similar configuration capabilities in between |
||
152 | config file and environment variables. |
||
153 | For consistency use the same variable name in the config file as |
||
154 | in the os environment. |
||
155 | For naming standards use all capitals and start with 'TABPY_' |
||
156 | """ |
||
157 | self.settings = {} |
||
158 | self.subdirectory = "" |
||
159 | self.tabpy_state = None |
||
160 | self.python_service = None |
||
161 | self.credentials = {} |
||
162 | |||
163 | parser = configparser.ConfigParser() |
||
164 | |||
165 | if os.path.isfile(config_file): |
||
166 | with open(config_file) as f: |
||
167 | parser.read_string(f.read()) |
||
168 | else: |
||
169 | logger.warning( |
||
170 | f'Unable to find config file at {config_file}, ' |
||
171 | 'using default settings.') |
||
172 | |||
173 | def set_parameter(settings_key, |
||
174 | config_key, |
||
175 | default_val=None, |
||
176 | check_env_var=False): |
||
177 | key_is_set = False |
||
178 | |||
179 | if config_key is not None and\ |
||
180 | parser.has_section('TabPy') and\ |
||
181 | parser.has_option('TabPy', config_key): |
||
182 | self.settings[settings_key] = parser.get('TabPy', config_key) |
||
183 | key_is_set = True |
||
184 | logger.debug( |
||
185 | f'Parameter {settings_key} set to ' |
||
186 | f'"{self.settings[settings_key]}" ' |
||
187 | 'from config file') |
||
188 | |||
189 | if not key_is_set and check_env_var: |
||
190 | val = os.getenv(config_key) |
||
191 | if val is not None: |
||
192 | self.settings[settings_key] = val |
||
193 | key_is_set = True |
||
194 | logger.debug( |
||
195 | f'Parameter {settings_key} set to ' |
||
196 | f'"{self.settings[settings_key]}" ' |
||
197 | 'from environment variable') |
||
198 | |||
199 | if not key_is_set and default_val is not None: |
||
200 | self.settings[settings_key] = default_val |
||
201 | key_is_set = True |
||
202 | logger.debug( |
||
203 | f'Parameter {settings_key} set to ' |
||
204 | f'"{self.settings[settings_key]}" ' |
||
205 | 'from default value') |
||
206 | |||
207 | if not key_is_set: |
||
208 | logger.debug( |
||
209 | f'Parameter {settings_key} is not set') |
||
210 | |||
211 | set_parameter(SettingsParameters.Port, ConfigParameters.TABPY_PORT, |
||
212 | default_val=9004, check_env_var=True) |
||
213 | set_parameter(SettingsParameters.ServerVersion, None, |
||
214 | default_val=__version__) |
||
215 | |||
216 | set_parameter(SettingsParameters.EvaluateTimeout, |
||
217 | ConfigParameters.TABPY_EVALUATE_TIMEOUT, |
||
218 | default_val=30) |
||
219 | try: |
||
220 | self.settings[SettingsParameters.EvaluateTimeout] = float( |
||
221 | self.settings[SettingsParameters.EvaluateTimeout]) |
||
222 | except ValueError: |
||
223 | logger.warning( |
||
224 | 'Evaluate timeout must be a float type. Defaulting ' |
||
225 | 'to evaluate timeout of 30 seconds.') |
||
226 | self.settings[SettingsParameters.EvaluateTimeout] = 30 |
||
227 | |||
228 | pkg_path = os.path.dirname(tabpy.__file__) |
||
229 | set_parameter(SettingsParameters.UploadDir, |
||
230 | ConfigParameters.TABPY_QUERY_OBJECT_PATH, |
||
231 | default_val=os.path.join(pkg_path, |
||
232 | 'tmp', 'query_objects'), |
||
233 | check_env_var=True) |
||
234 | if not os.path.exists(self.settings[SettingsParameters.UploadDir]): |
||
235 | os.makedirs(self.settings[SettingsParameters.UploadDir]) |
||
236 | |||
237 | # set and validate transfer protocol |
||
238 | set_parameter(SettingsParameters.TransferProtocol, |
||
239 | ConfigParameters.TABPY_TRANSFER_PROTOCOL, |
||
240 | default_val='http') |
||
241 | self.settings[SettingsParameters.TransferProtocol] =\ |
||
242 | self.settings[SettingsParameters.TransferProtocol].lower() |
||
243 | |||
244 | set_parameter(SettingsParameters.CertificateFile, |
||
245 | ConfigParameters.TABPY_CERTIFICATE_FILE) |
||
246 | set_parameter(SettingsParameters.KeyFile, |
||
247 | ConfigParameters.TABPY_KEY_FILE) |
||
248 | self._validate_transfer_protocol_settings() |
||
249 | |||
250 | # if state.ini does not exist try and create it - remove |
||
251 | # last dependence on batch/shell script |
||
252 | set_parameter(SettingsParameters.StateFilePath, |
||
253 | ConfigParameters.TABPY_STATE_PATH, |
||
254 | default_val=os.path.join(pkg_path, 'tabpy_server'), |
||
255 | check_env_var=True) |
||
256 | self.settings[SettingsParameters.StateFilePath] = os.path.realpath( |
||
257 | os.path.normpath( |
||
258 | os.path.expanduser( |
||
259 | self.settings[SettingsParameters.StateFilePath]))) |
||
260 | state_file_dir = self.settings[SettingsParameters.StateFilePath] |
||
261 | state_file_path = os.path.join(state_file_dir, 'state.ini') |
||
262 | if not os.path.isfile(state_file_path): |
||
263 | state_file_template_path = os.path.join( |
||
264 | pkg_path, 'tabpy_server', 'state.ini.template') |
||
265 | logger.debug(f'File {state_file_path} not found, creating from ' |
||
266 | f'template {state_file_template_path}...') |
||
267 | shutil.copy(state_file_template_path, state_file_path) |
||
268 | |||
269 | logger.info(f'Loading state from state file {state_file_path}') |
||
270 | tabpy_state = _get_state_from_file(state_file_dir) |
||
271 | self.tabpy_state = TabPyState( |
||
272 | config=tabpy_state, settings=self.settings) |
||
273 | |||
274 | self.python_service = PythonServiceHandler(PythonService()) |
||
275 | self.settings['compress_response'] = True |
||
276 | set_parameter(SettingsParameters.StaticPath, |
||
277 | ConfigParameters.TABPY_STATIC_PATH, |
||
278 | default_val='./') |
||
279 | self.settings[SettingsParameters.StaticPath] =\ |
||
280 | os.path.abspath(self.settings[SettingsParameters.StaticPath]) |
||
281 | logger.debug(f'Static pages folder set to ' |
||
282 | f'"{self.settings[SettingsParameters.StaticPath]}"') |
||
283 | |||
284 | # Set subdirectory from config if applicable |
||
285 | if tabpy_state.has_option("Service Info", "Subdirectory"): |
||
286 | self.subdirectory = "/" + \ |
||
287 | tabpy_state.get("Service Info", "Subdirectory") |
||
288 | |||
289 | # If passwords file specified load credentials |
||
290 | set_parameter(ConfigParameters.TABPY_PWD_FILE, |
||
291 | ConfigParameters.TABPY_PWD_FILE) |
||
292 | if ConfigParameters.TABPY_PWD_FILE in self.settings: |
||
293 | if not self._parse_pwd_file(): |
||
294 | msg = ('Failed to read passwords file ' |
||
295 | f'{self.settings[ConfigParameters.TABPY_PWD_FILE]}') |
||
296 | logger.critical(msg) |
||
297 | raise RuntimeError(msg) |
||
298 | else: |
||
299 | logger.info( |
||
300 | "Password file is not specified: " |
||
301 | "Authentication is not enabled") |
||
302 | |||
303 | features = self._get_features() |
||
304 | self.settings[SettingsParameters.ApiVersions] =\ |
||
305 | {'v1': {'features': features}} |
||
306 | |||
307 | set_parameter(SettingsParameters.LogRequestContext, |
||
308 | ConfigParameters.TABPY_LOG_DETAILS, |
||
309 | default_val='false') |
||
310 | self.settings[SettingsParameters.LogRequestContext] = ( |
||
311 | self.settings[SettingsParameters.LogRequestContext].lower() != |
||
312 | 'false') |
||
313 | call_context_state =\ |
||
314 | 'enabled' if self.settings[SettingsParameters.LogRequestContext]\ |
||
315 | else 'disabled' |
||
316 | logger.info(f'Call context logging is {call_context_state}') |
||
317 | |||
386 |