@@ -436,6 +436,28 @@ def str2value(self, value):
436436 return _val
437437 raise OptionValueError (self , value , self .class_description )
438438
439+ def validate (self , options ):
440+
441+ if self ._value in ("" , "xapian" ):
442+ try :
443+ import xapian
444+ except ImportError :
445+ # indexer is probably '' and xapian isn't present
446+ # so just return at end of method
447+ pass
448+ else :
449+ try :
450+ lang = options ["INDEXER_LANGUAGE" ]._value
451+ xapian .Stem (lang )
452+ except xapian .InvalidArgumentError :
453+ import textwrap
454+ lang_avail = b2s (xapian .Stem .get_available_languages ())
455+ languages = textwrap .fill (_ ("Valid languages: " ) +
456+ lang_avail , 75 ,
457+ subsequent_indent = " " )
458+ raise OptionValueError (options ["INDEXER_LANGUAGE" ],
459+ lang , languages )
460+
439461
440462class MailAddressOption (Option ):
441463
@@ -607,6 +629,22 @@ def get(self):
607629 "%s: %s." % (self .name , e .filename , e .args [1 ]))
608630 return self .str2value (_val )
609631
632+ def validate (self , options ):
633+ if self .name == 'MAIL_PASSWORD' :
634+ if options ['MAIL_USERNAME' ]._value :
635+ # MAIL_PASSWORD is an exception. It is mandatory only
636+ # if MAIL_USERNAME is set. So check only if username
637+ # is set.
638+ try :
639+ self .get ()
640+ except OptionUnsetError :
641+ # provide error message with link to MAIL_USERNAME
642+ raise OptionValueError (options ["MAIL_PASSWORD" ],
643+ "not defined" ,
644+ "Mail username is set, so this must be defined." )
645+ else :
646+ self .get ()
647+
610648
611649class WebUrlOption (Option ):
612650 """URL MUST start with http/https scheme and end with '/'"""
@@ -1479,6 +1517,10 @@ class Config:
14791517 # actual name of the config file. set on load.
14801518 filepath = os .path .join (HOME , INI_FILE )
14811519
1520+ # List of option names that need additional validation after
1521+ # all options are loaded.
1522+ option_validators = []
1523+
14821524 def __init__ (self , config_path = None , layout = None , settings = None ):
14831525 """Initialize confing instance
14841526
@@ -1552,6 +1594,9 @@ def add_option(self, option):
15521594 for _name in option .aliases :
15531595 self .options [_name ] = option
15541596
1597+ if hasattr (option , 'validate' ):
1598+ self .option_validators .append (option .name )
1599+
15551600 def update_option (self , name , klass ,
15561601 default = NODEFAULT , description = None ):
15571602 """Override behaviour of early created option.
@@ -1965,32 +2010,10 @@ def validator(self, options):
19652010 on each other. E.G. indexer_language can only be
19662011 validated if xapian indexer is used.
19672012 """
1968- if options ['INDEXER' ]._value in ("" , "xapian" ):
1969- try :
1970- import xapian
1971- except ImportError :
1972- # indexer is probably '' and xapian isn't present
1973- # so just return at end of method
1974- pass
1975- else :
1976- try :
1977- lang = options ["INDEXER_LANGUAGE" ]._value
1978- xapian .Stem (lang )
1979- except xapian .InvalidArgumentError :
1980- import textwrap
1981- lang_avail = b2s (xapian .Stem .get_available_languages ())
1982- languages = textwrap .fill (_ ("Valid languages: " ) +
1983- lang_avail , 75 ,
1984- subsequent_indent = " " )
1985- raise OptionValueError (options ["INDEXER_LANGUAGE" ],
1986- lang , languages )
19872013
1988- if options ['MAIL_USERNAME' ]._value != "" :
1989- # require password to be set
1990- if options ['MAIL_PASSWORD' ]._value is NODEFAULT :
1991- raise OptionValueError (options ["MAIL_PASSWORD" ],
1992- "not defined" ,
1993- "mail username is set, so this must be defined." )
2014+ for option in self .option_validators :
2015+ # validate() should throw an exception if there is an issue.
2016+ options [option ].validate (options )
19942017
19952018 def load (self , home_dir ):
19962019 """Load configuration from path designated by home_dir argument"""
0 commit comments