1# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html 2# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE 3 4 5import optparse # pylint: disable=deprecated-module 6from typing import Any, Dict, Tuple 7 8from pylint.config.option import _validate 9 10 11class UnsupportedAction(Exception): 12 """raised by set_option when it doesn't know what to do for an action""" 13 14 15class OptionsProviderMixIn: 16 """Mixin to provide options to an OptionsManager""" 17 18 # those attributes should be overridden 19 priority = -1 20 name = "default" 21 options: Tuple[Tuple[str, Dict[str, Any]], ...] = () 22 level = 0 23 24 def __init__(self): 25 self.config = optparse.Values() 26 self.load_defaults() 27 28 def load_defaults(self): 29 """initialize the provider using default values""" 30 for opt, optdict in self.options: 31 action = optdict.get("action") 32 if action != "callback": 33 # callback action have no default 34 if optdict is None: 35 optdict = self.get_option_def(opt) 36 default = optdict.get("default") 37 self.set_option(opt, default, action, optdict) 38 39 def option_attrname(self, opt, optdict=None): 40 """get the config attribute corresponding to opt""" 41 if optdict is None: 42 optdict = self.get_option_def(opt) 43 return optdict.get("dest", opt.replace("-", "_")) 44 45 def option_value(self, opt): 46 """get the current value for the given option""" 47 return getattr(self.config, self.option_attrname(opt), None) 48 49 def set_option(self, optname, value, action=None, optdict=None): 50 """method called to set an option (registered in the options list)""" 51 if optdict is None: 52 optdict = self.get_option_def(optname) 53 if value is not None: 54 value = _validate(value, optdict, optname) 55 if action is None: 56 action = optdict.get("action", "store") 57 if action == "store": 58 setattr(self.config, self.option_attrname(optname, optdict), value) 59 elif action in {"store_true", "count"}: 60 setattr(self.config, self.option_attrname(optname, optdict), 0) 61 elif action == "store_false": 62 setattr(self.config, self.option_attrname(optname, optdict), 1) 63 elif action == "append": 64 optname = self.option_attrname(optname, optdict) 65 _list = getattr(self.config, optname, None) 66 if _list is None: 67 if isinstance(value, (list, tuple)): 68 _list = value 69 elif value is not None: 70 _list = [] 71 _list.append(value) 72 setattr(self.config, optname, _list) 73 elif isinstance(_list, tuple): 74 setattr(self.config, optname, _list + (value,)) 75 else: 76 _list.append(value) 77 elif action == "callback": 78 optdict["callback"](None, optname, value, None) 79 else: 80 raise UnsupportedAction(action) 81 82 def get_option_def(self, opt): 83 """return the dictionary defining an option given its name""" 84 assert self.options 85 for option in self.options: 86 if option[0] == opt: 87 return option[1] 88 raise optparse.OptionError( 89 f"no such option {opt} in section {self.name!r}", opt 90 ) 91 92 def options_by_section(self): 93 """return an iterator on options grouped by section 94 95 (section, [list of (optname, optdict, optvalue)]) 96 """ 97 sections = {} 98 for optname, optdict in self.options: 99 sections.setdefault(optdict.get("group"), []).append( 100 (optname, optdict, self.option_value(optname)) 101 ) 102 if None in sections: 103 yield None, sections.pop(None) 104 for section, options in sorted(sections.items()): 105 yield section.upper(), options 106 107 def options_and_values(self, options=None): 108 if options is None: 109 options = self.options 110 for optname, optdict in options: 111 yield (optname, optdict, self.option_value(optname)) 112