changeset 6356:c26b9ce33ae3

issue2551123 - validate indexer_language in configuration.py Was validated in backends/indexer_xapian.py which would throw an error on access rather than on start. Added validator function to CoreConfig class that runs after config.ini is read. At this time we have access to the indexer setting so can determine if xapian is actually going to be used. Moved test into test/test_config.py and pulled validation code from indexer_xapian.py and test/test_indexer.py.
author John Rouillard <rouilj@ieee.org>
date Mon, 29 Mar 2021 22:47:54 -0400
parents ac5a6ffa377b
children c985ed52ca2d
files roundup/backends/indexer_xapian.py roundup/configuration.py test/test_config.py test/test_indexer.py
diffstat 4 files changed, 88 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/roundup/backends/indexer_xapian.py	Mon Mar 29 20:43:22 2021 -0400
+++ b/roundup/backends/indexer_xapian.py	Mon Mar 29 22:47:54 2021 -0400
@@ -22,18 +22,6 @@
         self.reindex = 0
         self.transaction_active = False
 
-        # self.language defined in IndexerBase.__init__
-        # validate it here
-        try:
-            xapian.Stem(self.language)
-        except xapian.InvalidArgumentError:
-            raise ValueError(
-                _("Invalid indexer_language %(lang)s for xapian indexer\n"
-                  "Valid languages: %(valid)s") % {
-                      "lang": self.language,
-                      "valid": b2s(xapian.Stem.get_available_languages()) }
-            )
-
     def _get_database(self):
         index = os.path.join(self.db_path, 'text-index')
         for n in range(10):
--- a/roundup/configuration.py	Mon Mar 29 20:43:22 2021 -0400
+++ b/roundup/configuration.py	Mon Mar 29 22:47:54 2021 -0400
@@ -20,6 +20,7 @@
 from roundup.anypy.strings import b2s
 import roundup.anypy.random_ as random_
 import binascii
+from roundup.i18n import _
 
 from roundup.backends import list_backends
 
@@ -1844,12 +1845,49 @@
         logger.handlers = [hdlr]
         logger.setLevel(self["LOGGING_LEVEL"] or "ERROR")
 
+    def validator(self, options):
+        """ Validate options once all options are loaded.
+
+            Used to validate settings when options are dependent
+            on each other. E.G. indexer_language can only be
+            validated if xapian indexer is used.
+        """
+        if options['INDEXER']._value in ("", "xapian"):
+            try:
+                import xapian
+            except ImportError:
+                # indexer is probably '' and xapian isn't present
+                # so just return at end of method
+                pass
+            else:
+                try:
+                    lang = options["INDEXER_LANGUAGE"]._value
+                    xapian.Stem(lang)
+                except xapian.InvalidArgumentError:
+                    import textwrap
+                    lang_avail = b2s(xapian.Stem.get_available_languages())
+                    languages = textwrap.fill(_("Valid languages: ") +
+                                              lang_avail, 75,
+                                              subsequent_indent="   ")
+                    raise ValueError(
+                        _("Invalid indexer_language '%(lang)s' in config.ini for xapian indexer\n\n"
+                          "%(valid)s") % {
+                              "lang": lang,
+                              "valid": languages
+                          }
+                    )
+
     def load(self, home_dir):
         """Load configuration from path designated by home_dir argument"""
         if os.path.isfile(os.path.join(home_dir, self.INI_FILE)):
             self.load_ini(home_dir)
         else:
             raise NoConfigError(home_dir)
+
+        # validator does inter-setting validation checks.
+        # when there are dependencies between options.
+        self.validator(self.options)
+
         self.init_logging()
         self.ext = UserConfig(os.path.join(home_dir, "extensions"))
         self.detectors = UserConfig(os.path.join(home_dir, "detectors"))
--- a/test/test_config.py	Mon Mar 29 20:43:22 2021 -0400
+++ b/test/test_config.py	Mon Mar 29 22:47:54 2021 -0400
@@ -284,3 +284,53 @@
                           self.dirname)
 
 
+    def testInvalidIndexer_language(self):
+        """ make sure we have a reasonable error message if
+            invalid language is specified """
+
+        # change the indexer_language value to an invalid value.
+        import fileinput
+        for line in fileinput.input(os.path.join(self.dirname, "config.ini"),
+                                    inplace=True):
+          if line.startswith("indexer_language = "):
+              print("indexer_language = NO_LANG")
+              continue
+          print(line[:-1]) # remove trailing \n
+
+        config = configuration.CoreConfig()
+        
+        # Note this should raise OptionValueError, but
+        # the test fot this error occurs too late to have
+        # a valid option still available. So raise ValueError.
+        with self.assertRaises(ValueError) as cm:
+            config.load(self.dirname)
+
+        print(cm.exception)
+        self.assertIn("ValueError", repr(cm.exception))
+        # look for failing language
+        self.assertIn("NO_LANG", cm.exception.args[0])
+        # look for supported language
+        self.assertIn("english", cm.exception.args[0])
+
+    def testLoadConfig(self):
+        """ run load to validate config """
+
+        config = configuration.CoreConfig()
+        
+        config.load(self.dirname)
+
+        with self.assertRaises(configuration.InvalidOptionError) as cm:
+            c = config['indexer_language']
+        print(cm.exception)
+        self.assertIn("indexer_language", repr(cm.exception))
+
+        self.assertEqual(config['HTML_VERSION'], 'html4')
+        self.assertEqual(config[('main', 'html_version')], 'html4')
+
+        self.assertEqual(config['WEB_COOKIE_TAKES_PRECEDENCE'], 0)
+        self.assertEqual(config[('web','cookie_takes_precedence')], 0)
+        
+
+
+
+
--- a/test/test_indexer.py	Mon Mar 29 20:43:22 2021 -0400
+++ b/test/test_indexer.py	Mon Mar 29 22:47:54 2021 -0400
@@ -195,26 +195,6 @@
         self.dex = Indexer(db)
     def tearDown(self):
         shutil.rmtree('test-index')
-    def test_invalid_language(self):
-        """ make sure we have a reasonable error message if
-            invalid language is specified """
-        l = db.config[('main', 'indexer_language')]
-        db.config[('main', 'indexer_language')] = "NO_LANG"
-        from roundup.backends.indexer_xapian import Indexer
-        with self.assertRaises(ValueError) as cm:
-            Indexer(db)
-        # note if Indexer(db) doesn't return ValueError
-        # all Xapian tests after this point will fail.
-        # because a valid langage will not be set.
-        # reset the valid language.
-        db.config[('main', 'indexer_language')] =  l
-
-        print(cm)
-        self.assertIn("ValueError", repr(cm.exception))
-        # look for failing language
-        self.assertIn("NO_LANG", cm.exception.args[0])
-        # look for supported language
-        self.assertIn("english", cm.exception.args[0])
 
 class RDBMSIndexerTest(object):
     def setUp(self):

Roundup Issue Tracker: http://roundup-tracker.org/