📄 optionsclass.py
字号:
def merge_file(self, filename): import ConfigParser c = ConfigParser.ConfigParser() c.read(filename) for sect in c.sections(): for opt in c.options(sect): value = c.get(sect, opt) section = sect option = opt if not self._options.has_key((section, option)): if option.startswith('x-'): # try setting option without the x- prefix option = option[2:] if self._options.has_key((section, option)): self.convert_and_set(section, option, value) # not an error if an X- option is missing else: option = 'x-' + option # going the other way, if the option has been # deprecated, set its x-prefixed version and # emit a warning if self._options.has_key((section, option)): self.convert_and_set(section, option, value) self._report_deprecated_error(section, opt) else: print >> sys.stderr, ( "warning: Invalid option %s in" " section %s in file %s" % (opt, sect, filename)) else: self.convert_and_set(section, option, value) # not strictly necessary, but convenient shortcuts to self._options def display_name(self, sect, opt): '''A name for the option suitable for display to a user.''' return self._options[sect, opt.lower()].display_name() def default(self, sect, opt): '''The default value for the option.''' return self._options[sect, opt.lower()].default() def doc(self, sect, opt): '''Documentation for the option.''' return self._options[sect, opt.lower()].doc() def valid_input(self, sect, opt): '''Valid values for the option.''' return self._options[sect, opt.lower()].valid_input() def no_restore(self, sect, opt): '''Do not restore this option when restoring to defaults.''' return self._options[sect, opt.lower()].no_restore() def is_valid(self, sect, opt, value): '''Check if this is a valid value for this option.''' return self._options[sect, opt.lower()].is_valid(value) def multiple_values_allowed(self, sect, opt): '''Multiple values are allowed for this option.''' return self._options[sect, opt.lower()].multiple_values_allowed() def is_boolean(self, sect, opt): '''The option is a boolean value. (Support for Python 2.2).''' return self._options[sect, opt.lower()].is_boolean() def convert(self, sect, opt, value): '''Convert value from a string to the appropriate type.''' return self._options[sect, opt.lower()].convert(value) def unconvert(self, sect, opt): '''Convert value from the appropriate type to a string.''' return self._options[sect, opt.lower()].unconvert() def get_option(self, sect, opt): '''Get an option.''' if self.conversion_table.has_key((sect, opt)): sect, opt = self.conversion_table[sect, opt] return self._options[sect, opt.lower()] def get(self, sect, opt): '''Get an option value.''' if self.conversion_table.has_key((sect, opt.lower())): sect, opt = self.conversion_table[sect, opt.lower()] return self.get_option(sect, opt.lower()).get() def __getitem__(self, key): return self.get(key[0], key[1]) def set(self, sect, opt, val=None): '''Set an option.''' if self.conversion_table.has_key((sect, opt.lower())): sect, opt = self.conversion_table[sect, opt.lower()] # Annoyingly, we have a special case. The notate_to and # notate_subject allowed values have to be set to the same # values as the header_x_ options, but this can't be done # (AFAIK) dynmaically. If this isn't the case, then if the # header_x_string values are changed, the notate_ options don't # work. Outlook Express users like both of these options...so # we fix it here. See also sf #944109. # This code was originally in Options.py, after loading in the # options. But that doesn't work, because if we are setting # both in a config file, we need it done immediately. # We now need the hack here, *and* in UserInterface.py # For the moment, this will do. Use a real mail client, for # goodness sake! if sect == "Headers" and opt in ("notate_to", "notate_subject"): header_strings = (self.get("Headers", "header_ham_string"), self.get("Headers", "header_spam_string"), self.get("Headers", "header_unsure_string")) self._options[sect, opt.lower()].set(val) return if self.is_valid(sect, opt, val): self._options[sect, opt.lower()].set(val) else: print >> sys.stderr, ("Attempted to set [%s] %s with " "invalid value %s (%s)" % (sect, opt.lower(), val, type(val))) def set_from_cmdline(self, arg, stream=None): """Set option from colon-separated sect:opt:val string. If optional stream arg is not None, error messages will be displayed on stream, otherwise KeyErrors will be propagated up the call chain. """ sect, opt, val = arg.split(':', 2) opt = opt.lower() try: val = self.convert(sect, opt, val) except (KeyError, TypeError), msg: if stream is not None: self._report_option_error(sect, opt, val, stream, msg) else: raise else: self.set(sect, opt, val) def _report_deprecated_error(self, sect, opt): print >> sys.stderr, ( "Warning: option %s in section %s is deprecated" % (opt, sect)) def _report_option_error(self, sect, opt, val, stream, msg): if sect in self.sections(): vopts = self.options(True) vopts = [v.split(']', 1)[1] for v in vopts if v.startswith('[%s]'%sect)] if opt not in vopts: print >> stream, "Invalid option:", opt print >> stream, "Valid options for", sect, "are:" vopts = ', '.join(vopts) vopts = wrap(vopts) for line in vopts: print >> stream, ' ', line else: print >> stream, "Invalid value:", msg else: print >> stream, "Invalid section:", sect print >> stream, "Valid sections are:" vsects = ', '.join(self.sections()) vsects = wrap(vsects) for line in vsects: print >> stream, ' ', line def __setitem__(self, key, value): self.set(key[0], key[1], value) def sections(self): '''Return an alphabetical list of all the sections.''' all = [] for sect, opt in self._options.keys(): if sect not in all: all.append(sect) all.sort() return all def options_in_section(self, section): '''Return an alphabetical list of all the options in this section.''' all = [] for sect, opt in self._options.keys(): if sect == section: all.append(opt) all.sort() return all def options(self, prepend_section_name=False): '''Return an alphabetical list of all the options, optionally prefixed with [section_name]''' all = [] for sect, opt in self._options.keys(): if prepend_section_name: all.append('[' + sect + ']' + opt) else: all.append(opt) all.sort() return all def display(self, add_comments=False): '''Display options in a config file form.''' output = StringIO.StringIO() keys = self._options.keys() keys.sort() currentSection = None for sect, opt in keys: if sect != currentSection: if currentSection is not None: output.write('\n') output.write('[') output.write(sect) output.write("]\n") currentSection = sect if add_comments: doc = self._options[sect, opt].doc() if not doc: doc = "No information available, sorry." doc = re.sub(r"\s+", " ", doc) output.write("\n# %s\n" % ("\n# ".join(wrap(doc)),)) self._options[sect, opt].write_config(output) return output.getvalue() def _display_nice(self, section, option, formatter): '''Display a nice output of the options''' # Given that the Options class is no longer as nice looking # as it once was, this returns all the information, i.e. # the doc, default values, and so on output = StringIO.StringIO() # when section and option are both specified, this # is nothing more than a call to as_nice_string if section is not None and option is not None: opt = self._options[section, option.lower()] output.write(getattr(opt, formatter)(section)) return output.getvalue() all = self._options.keys() all.sort() for sect, opt in all: if section is not None and sect != section: continue opt = self._options[sect, opt.lower()] output.write(getattr(opt, formatter)(sect)) return output.getvalue() def display_full(self, section=None, option=None): '''Display options including all information.''' return self._display_nice(section, option, 'as_nice_string') def output_for_docs(self, section=None, option=None): '''Return output suitable for inserting into documentation for the available options.''' return self._display_nice(section, option, 'as_documentation_string')# These are handy references to commonly used regex/tuples defining# permitted values. Although the majority of options use one of these,# you may use any regex or tuple you wish.HEADER_NAME = r"[\w\.\-\*]+"HEADER_VALUE = r".+"INTEGER = r"[\d]+" # actually, a *positive* integerREAL = r"[\d]+[\.]?[\d]*" # likewise, a *positive* realBOOLEAN = (False, True)SERVER = r"([\w\.\-]+(:[\d]+)?)" # in the form server:portPORT = r"[\d]+"EMAIL_ADDRESS = r"[\w\-\.]+@[\w\-\.]+"PATH = r"[\w \$\.\-~:\\/\*\@\=]+"VARIABLE_PATH = PATH + r"%"FILE = r"[\S]+"FILE_WITH_PATH = PATHIP_LIST = r"\*|localhost|((\*|[01]?\d\d?|2[0-4]\d|25[0-5])\.(\*|[01]?\d" \ r"\d?|2[0-4]\d|25[0-5])\.(\*|[01]?\d\d?|2[0-4]\d|25[0-5])\.(\*" \ r"|[01]?\d\d?|2[0-4]\d|25[0-5]),?)+"# IMAP seems to allow any character at all in a folder name,# but we want to use the comma as a delimiter for lists, so# we don't allow this. If anyone has folders with commas in the# names, please let us know and we'll figure out something else.# ImapUI.py prints out a warning if this is the case.IMAP_FOLDER = r"[^,]+"# IMAP's astring should also be valid in the form:# "{" number "}" CRLF *CHAR8# where number represents the number of CHAR8 octets# but this is too complex for us at the moment.IMAP_ASTRING = []for i in range(1, 128): if not chr(i) in ['"', '\\', '\n', '\r']: IMAP_ASTRING.append(chr(i))IMAP_ASTRING = r"\"?[" + re.escape(''.join(IMAP_ASTRING)) + r"]+\"?"# Similarly, each option must specify whether it should be reset to# this value on a "reset to defaults" command. Most should, but with some# like a server name that defaults to "", this would be pointless.# Again, for ease of reading, we define these here:RESTORE = TrueDO_NOT_RESTORE = FalseOCRAD_CHARSET = r"ascii|iso-8859-9|iso-8859-15"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -