changeset 6004:55f5060e0508

flake8 formatting fixes; use isinstance rather than type equality.
author John Rouillard <rouilj@ieee.org>
date Sat, 28 Dec 2019 13:01:14 -0500
parents 48a1f919f894
children 292c9dfd06bd
files roundup/configuration.py
diffstat 1 files changed, 95 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/roundup/configuration.py	Sat Dec 28 12:50:11 2019 -0500
+++ b/roundup/configuration.py	Sat Dec 28 13:01:14 2019 -0500
@@ -8,11 +8,6 @@
 # where not expected by the Python code.  Thus, a version check is
 # used here instead of try/except.
 import sys
-if sys.version_info[0] > 2:
-    import configparser			# Python 3
-else:
-    import ConfigParser as configparser	# Python 2
-
 import getopt
 import imp
 import logging, logging.config
@@ -29,13 +24,20 @@
 
 from roundup.backends import list_backends
 
+if sys.version_info[0] > 2:
+    import configparser			 # Python 3
+else:
+    import ConfigParser as configparser  # Python 2
+
 # XXX i don't think this module needs string translation, does it?
 
 ### Exceptions
 
+
 class ConfigurationError(BaseException):
     pass
 
+
 class NoConfigError(ConfigurationError):
 
     """Raised when configuration loading fails
@@ -48,6 +50,7 @@
         return "No valid configuration files found in directory %s" \
             % self.args[0]
 
+
 class InvalidOptionError(ConfigurationError, KeyError, AttributeError):
 
     """Attempted access to non-existing configuration option
@@ -64,6 +67,7 @@
     def __str__(self):
         return "Unsupported configuration option: %s" % self.args[0]
 
+
 class OptionValueError(ConfigurationError, ValueError):
 
     """Raised upon attempt to assign an invalid value to config option
@@ -81,6 +85,7 @@
             _rv += "\n".join(("",) + _args[2:])
         return _rv
 
+
 class OptionUnsetError(ConfigurationError):
 
     """Raised when no Option value is available - neither set, nor default
@@ -92,6 +97,7 @@
     def __str__(self):
         return "%s is not set and has no default" % self.args[0].name
 
+
 class UnsetDefaultValue:
 
     """Special object meaning that default value for Option is not specified"""
@@ -99,13 +105,16 @@
     def __str__(self):
         return "NO DEFAULT"
 
+
 NODEFAULT = UnsetDefaultValue()
 
+
 def create_token(size=32):
     return b2s(binascii.b2a_base64(random_.token_bytes(size)).strip())
 
 ### Option classes
 
+
 class Option:
 
     """Single configuration option.
@@ -141,8 +150,7 @@
     class_description = None
 
     def __init__(self, config, section, setting,
-        default=NODEFAULT, description=None, aliases=None
-    ):
+                 default=NODEFAULT, description=None, aliases=None):
         self.config = config
         self.section = section
         self.setting = setting.lower()
@@ -261,6 +269,7 @@
                 self.set(getattr(config, _name))
                 break
 
+
 class BooleanOption(Option):
 
     """Boolean option: yes or no"""
@@ -274,7 +283,7 @@
             return "no"
 
     def str2value(self, value):
-        if type(value) == type(""):
+        if isinstance(value, type("")):
             _val = value.lower()
             if _val in ("yes", "true", "on", "1"):
                 _val = 1
@@ -286,6 +295,7 @@
             _val = value and 1 or 0
         return _val
 
+
 class WordListOption(Option):
 
     """List of strings"""
@@ -298,6 +308,7 @@
     def str2value(self, value):
         return value.split(',')
 
+
 class RunDetectorOption(Option):
 
     """When a detector is run: always, never or for new items only"""
@@ -311,6 +322,7 @@
         else:
             raise OptionValueError(self, value, self.class_description)
 
+
 class CsrfSettingOption(Option):
 
     """How should a csrf measure be enforced: required, yes, logfailure, no"""
@@ -324,6 +336,7 @@
         else:
             raise OptionValueError(self, value, self.class_description)
 
+
 class SameSiteSettingOption(Option):
 
     """How should the SameSite cookie setting be set: strict, lax
@@ -337,10 +350,11 @@
             return _val.capitalize()
         else:
             raise OptionValueError(self, value, self.class_description)
-        
+
+
 class DatabaseBackend(Option):
     """handle exact text of backend and make sure it's available"""
-    class_description = "Available backends: %s"%", ".join(list_backends())
+    class_description = "Available backends: %s" % ", ".join(list_backends())
 
     def str2value(self, value):
         _val = value.lower()
@@ -349,9 +363,16 @@
         else:
             raise OptionValueError(self, value, self.class_description)
 
+
 class HtmlToTextOption(Option):
 
-    """What module should be used to convert emails with only text/html parts into text for display in roundup. Choose from beautifulsoup 4, dehtml - the internal code or none to disable html to text conversion. If beautifulsoup chosen but not available, dehtml will be used."""
+    """What module should be used to convert emails with only text/html
+    parts into text for display in roundup. Choose from beautifulsoup
+    4, dehtml - the internal code or none to disable html to text
+    conversion. If beautifulsoup chosen but not available, dehtml will
+    be used.
+
+    """
 
     class_description = "Allowed values: beautifulsoup, dehtml, none"
 
@@ -362,9 +383,11 @@
         else:
             raise OptionValueError(self, value, self.class_description)
 
+
 class EmailBodyOption(Option):
 
-    """When to replace message body or strip quoting: always, never or for new items only"""
+    """When to replace message body or strip quoting: always, never
+    or for new items only"""
 
     class_description = "Allowed values: yes, no, new"
 
@@ -375,13 +398,14 @@
         else:
             raise OptionValueError(self, value, self.class_description)
 
+
 class IsolationOption(Option):
     """Database isolation levels"""
 
     allowed = ['read uncommitted', 'read committed', 'repeatable read',
-        'serializable']
-    class_description = "Allowed values: %s" % ', '.join ("'%s'" % a
-        for a in allowed)
+               'serializable']
+    class_description = "Allowed values: %s" % ', '.join("'%s'" % a
+                                                         for a in allowed)
 
     def str2value(self, value):
         _val = value.lower()
@@ -389,6 +413,7 @@
             return _val
         raise OptionValueError(self, value, self.class_description)
 
+
 class MailAddressOption(Option):
 
     """Email address
@@ -404,6 +429,7 @@
             _val = "@".join((_val, self.config["MAIL_DOMAIN"]))
         return _val
 
+
 class FilePathOption(Option):
 
     """File or directory path name
@@ -421,6 +447,7 @@
             _val = os.path.join(self.config["HOME"], _val)
         return _val
 
+
 class MultiFilePathOption(Option):
 
     """List of space seperated File or directory path name
@@ -430,8 +457,8 @@
 
     """
 
-    class_description = "The space separated paths may be either absolute or\n" \
-        "relative to the directory containing this config file."
+    class_description = "The space separated paths may be either absolute\n" \
+        "or relative to the directory containing this config file."
 
     def get(self):
         pathlist = []
@@ -446,6 +473,7 @@
         else:
             return None
 
+
 class FloatNumberOption(Option):
 
     """Floating point numbers"""
@@ -455,7 +483,7 @@
             return float(value)
         except ValueError:
             raise OptionValueError(self, value,
-                "Floating point number required")
+                                   "Floating point number required")
 
     def _value2str(self, value):
         _val = str(value)
@@ -464,6 +492,7 @@
             _val = _val[:-2]
         return _val
 
+
 class IntegerNumberOption(Option):
 
     """Integer numbers"""
@@ -474,6 +503,7 @@
         except ValueError:
             raise OptionValueError(self, value, "Integer number required")
 
+
 class IntegerNumberGeqZeroOption(Option):
 
     """Integer numbers greater than or equal to zero."""
@@ -486,10 +516,11 @@
                       "Integer number greater than or equal to zero required")
             return v
         except OptionValueError:
-            raise # pass through subclass
+            raise  # pass through subclass
         except ValueError:
             raise OptionValueError(self, value, "Integer number required")
 
+
 class OctalNumberOption(Option):
 
     """Octal Integer numbers"""
@@ -498,25 +529,28 @@
         try:
             return int(value, 8)
         except ValueError:
-            raise OptionValueError(self, value, "Octal Integer number required")
+            raise OptionValueError(self, value,
+                                   "Octal Integer number required")
 
     def _value2str(self, value):
         return oct(value)
 
+
 class MandatoryOption(Option):
     """Option must not be empty"""
     def str2value(self, value):
         if not value:
-            raise OptionValueError(self,value,"Value must not be empty.")
+            raise OptionValueError(self, value, "Value must not be empty.")
         else:
             return value
 
+
 class WebUrlOption(Option):
     """URL MUST start with http/https scheme and end with '/'"""
 
     def str2value(self, value):
         if not value:
-            raise OptionValueError(self,value,"Value must not be empty.")
+            raise OptionValueError(self, value, "Value must not be empty.")
 
         error_msg = ''
         if not value.startswith(('http://', 'https://')):
@@ -526,10 +560,11 @@
             error_msg += "Value must end with /."
 
         if error_msg:
-            raise OptionValueError(self,value,error_msg)
+            raise OptionValueError(self, value, error_msg)
         else:
             return value
 
+
 class NullableOption(Option):
 
     """Option that is set to None if its string value is one of NULL strings
@@ -545,12 +580,11 @@
     NULL_STRINGS = ("",)
 
     def __init__(self, config, section, setting,
-        default=NODEFAULT, description=None, aliases=None,
-        null_strings=NULL_STRINGS
-    ):
+                 default=NODEFAULT, description=None, aliases=None,
+                 null_strings=NULL_STRINGS):
         self.null_strings = list(null_strings)
         Option.__init__(self, config, section, setting, default,
-            description, aliases)
+                        description, aliases)
 
     def str2value(self, value):
         if value in self.null_strings:
@@ -564,6 +598,7 @@
         else:
             return value
 
+
 class NullableFilePathOption(NullableOption, FilePathOption):
 
     # .get() and class_description are from FilePathOption,
@@ -571,6 +606,7 @@
     class_description = FilePathOption.class_description
     # everything else taken from NullableOption (inheritance order)
 
+
 class TimezoneOption(Option):
 
     class_description = \
@@ -595,7 +631,7 @@
                     "Timezone name or numeric hour offset required")
         return value
 
-    
+
 class RegExpOption(Option):
 
     """Regular Expression option (value is Regular Expression Object)"""
@@ -605,12 +641,11 @@
     RE_TYPE = type(re.compile(""))
 
     def __init__(self, config, section, setting,
-        default=NODEFAULT, description=None, aliases=None,
-        flags=0,
-    ):
+                 default=NODEFAULT, description=None, aliases=None,
+                 flags=0):
         self.flags = flags
         Option.__init__(self, config, section, setting, default,
-            description, aliases)
+                        description, aliases)
 
     def _value2str(self, value):
         assert isinstance(value, self.RE_TYPE)
@@ -637,6 +672,8 @@
 # setting, default, [description, [aliases]]
 # Note: aliases should only exist in historical options for backwards
 # compatibility - new options should *not* have aliases!
+
+
 SETTINGS = (
     ("main", (
         (FilePathOption, "database", "db", "Database directory path."),
@@ -684,13 +721,13 @@
             "This is a comma-separated string of role names"
             " (e.g. 'Admin,User')."),
         (Option, "obsolete_history_roles", "Admin",
-	    "On schema changes, properties or classes in the history may\n"
-	    "become obsolete.  Since normal access permissions do not apply\n"
-	    "(we don't know if a user should see such a property or class)\n"
-	    "a list of roles is specified here that are allowed to see\n"
-	    "these obsolete properties in the history. By default only the\n"
-	    "admin role may see these history entries, you can make them\n"
-	    "visible to all users by adding, e.g., the 'User' role here."),
+            "On schema changes, properties or classes in the history may\n"
+            "become obsolete.  Since normal access permissions do not apply\n"
+            "(we don't know if a user should see such a property or class)\n"
+            "a list of roles is specified here that are allowed to see\n"
+            "these obsolete properties in the history. By default only the\n"
+            "admin role may see these history entries, you can make them\n"
+            "visible to all users by adding, e.g., the 'User' role here."),
         (Option, "error_messages_to", "user",
             # XXX This description needs better wording,
             #   with explicit allowed values list.
@@ -771,8 +808,8 @@
             "who updated the issue, but it could be useful in some\n"
             "unusual circumstances.\n"
             "If set to some other value, the value is used as the reply-to\n"
-            "address. It must be a valid RFC2822 address or people will not be\n"
-            "able to reply."),
+            "address. It must be a valid RFC2822 address or people will not\n"
+            "be able to reply."),
         (NullableOption, "language", "",
             "Default locale name for this tracker.\n"
             "If this option is not set, the language is determined\n"
@@ -808,7 +845,7 @@
             "is available before sending confirmation email.\n"
             "Usually a username conflict is detected when\n"
             "confirming the registration. Disabled by default as\n"
-            "it can be used for guessing existing usernames.\n" ),
+            "it can be used for guessing existing usernames.\n"),
         (SameSiteSettingOption, 'samesite_cookie_setting', "Lax",
             """Set the mode of the SameSite cookie option for
 the session cookie. Choices are 'Lax' or
@@ -832,7 +869,7 @@
 no special meaning and will yield an error message."""),
         (IntegerNumberGeqZeroOption, 'api_calls_per_interval', "0",
          "Limit API calls per api_interval_in_sec seconds to\n"
-         "this number.\n"         
+         "this number.\n"
          "Determines the burst rate and the rate that new api\n"
          "calls will be made available. If set to 360 and\n"
          "api_intervals_in_sec is set to 3600, the 361st call in\n"
@@ -968,8 +1005,8 @@
             "If less than 256 bits (32 characters) in length it will\n"
             "disable use of jwt. Changing this invalidates all jwts\n"
             "issued by the roundup instance requiring *all* users to\n"
-            "generate new jwts. This is experimental and disabled by default.\n"
-            "It must be persistent across application restarts.\n"),
+            "generate new jwts. This is experimental and disabled by\n"
+            "default. It must be persistent across application restarts.\n"),
     )),
     ("rdbms", (
         (DatabaseBackend, 'backend', NODEFAULT,
@@ -1097,7 +1134,8 @@
             "If this is false but add_authorinfo is true, only the name\n"
             "of the actor is added which protects the mail address of the\n"
             "actor from being exposed at mail archives, etc."),
-    ), "Outgoing email options.\nUsed for nosy messages and approval requests"),
+    ), "Outgoing email options.\n"
+     "Used for nosy messages and approval requests"),
     ("mailgw", (
         (EmailBodyOption, "keep_quoted_text", "yes",
             "Keep email citations when accepting messages.\n"
@@ -1267,6 +1305,7 @@
 
 ### Configuration classes
 
+
 class Config:
 
     """Base class for configuration objects.
@@ -1366,8 +1405,7 @@
             self.options[_name] = option
 
     def update_option(self, name, klass,
-        default=NODEFAULT, description=None
-    ):
+                      default=NODEFAULT, description=None):
         """Override behaviour of early created option.
 
         Parameters:
@@ -1397,7 +1435,7 @@
         value = option.value2str(current=1)
         # resurrect the option
         option = klass(self, option.section, option.setting,
-            default=default, description=description)
+                       default=default, description=description)
         # apply the value
         option.set(value)
         # incorporate new option
@@ -1413,8 +1451,7 @@
     # Allows automatic creation of configuration files like this:
     #  roundup-server -p 8017 -u roundup --save-config
     def getopt(self, args, short_options="", long_options=(),
-        config_load_options=("C", "config"), **options
-    ):
+               config_load_options=("C", "config"), **options):
         """Apply options specified in command line arguments.
 
         Parameters:
@@ -1483,7 +1520,7 @@
         # apply options
         extra_options = []
         for (opt, arg) in optlist:
-            if (opt in booleans): # and not arg
+            if (opt in booleans):  # and not arg
                 arg = "yes"
             try:
                 name = cfg_names[opt]
@@ -1594,7 +1631,7 @@
         for section in self.sections:
             comment = self.section_descriptions.get(section, None)
             if comment:
-                _fp.write("\n# ".join([""] + comment.split("\n")) +"\n")
+                _fp.write("\n# ".join([""] + comment.split("\n")) + "\n")
             else:
                 # no section comment - just leave a blank line between sections
                 _fp.write("\n")
@@ -1643,9 +1680,8 @@
 
         """
         return [self.options[(_section, _name)]
-            for _section in self.sections
-            for _name in self._get_section_options(_section)
-        ]
+                for _section in self.sections
+                for _name in self._get_section_options(_section)]
 
     def keys(self):
         """Return the list of "canonical" names of the options
@@ -1671,6 +1707,7 @@
     def __getattr__(self, name):
         return self[name]
 
+
 class UserConfig(Config):
 
     """Configuration for user extensions.
@@ -1690,9 +1727,10 @@
         for section in config.sections():
             for name in config.options(section):
                 if ((section, name) not in preset) \
-                and (name not in defaults):
+                   and (name not in defaults):
                     self.add_option(Option(self, section, name))
 
+
 class CoreConfig(Config):
 
     """Roundup instance configuration.

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