#!/usr/bin/env python # -*- coding: utf-8 -*- # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # Example .impalarc file: # # [impala] # impalad=localhost:21002 # verbose=false # # [impala.query_options] # EXPLAIN_LEVEL=2 # MT_DOP=2 from __future__ import print_function, unicode_literals import sys try: from configparser import ConfigParser # python3 except ImportError: from ConfigParser import ConfigParser # python2 from impala_shell_config_defaults import impala_shell_defaults from optparse import OptionParser, SUPPRESS_HELP class ConfigFileFormatError(Exception): """Raised when the config file cannot be read by ConfigParser.""" pass class InvalidOptionValueError(Exception): """Raised when an option contains an invalid value.""" pass def parse_bool_option(value): """Returns True for '1' and 'True', and False for '0' and 'False'. Throws ValueError for other values. """ if value.lower() in ["true", "1"]: return True elif value.lower() in ["false", "0"]: return False else: raise InvalidOptionValueError("Unexpected value in configuration file. '" + value + "' is not a valid value for a boolean option.") def parse_shell_options(options, defaults, option_list): """Filters unknown options and converts some values from string to their corresponding python types (booleans and None). 'option_list' contains the list of valid options, and 'defaults' is used to deduce the type of some options (only bool at the moment). Returns a dictionary with option names as keys and option values as values. """ # Build a dictionary that maps short and long option name to option for a quick lookup. option_dests = dict() for option in option_list: if len(option._short_opts) > 0: option_dests[option._short_opts[0][1:]] = option if len(option._long_opts) > 0: option_dests[option._long_opts[0][2:]] = option if option.dest not in option_dests: # Allowing dest name for backward compatibility. option_dests[option.dest] = option result = {} for option, value in options: opt = option_dests.get(option) if opt is None: warn_msg = ( "WARNING: Unable to read configuration file correctly. " "Ignoring unrecognized config option: '%s'" % option ) print('\n{0}'.format(warn_msg), file=sys.stderr) elif isinstance(defaults.get(option), bool) or \ opt.action == "store_true" or opt.action == "store_false": result[option] = parse_bool_option(value) elif opt.action == "append": result[option] = value.split(",%s=" % option) elif value.lower() == "none": result[option] = None else: result[option] = value return result def get_config_from_file(config_filename, option_list): """Reads contents of configuration file Two config sections are supported: "[impala]": Overrides the defaults of the shell arguments. Unknown options are filtered and some values are converted from string to their corresponding python types (booleans and None). Multiple flags are appended with ",option_name=" as its delimiter, e.g. The delimiter is for multiple options is ,