def run_validation(self, value): if not isinstance(value, (list, tuple)): raise ValidationError( 'Invalid Plugins configuration. Expected a list of plugins', ) plgins = plugins.PluginCollection() for item in value: if isinstance(item, dict): if len(item) > 1: raise ValidationError('Invalid Plugins configuration') name, cfg = item.popitem() cfg = cfg or {} # Users may define a null (None) config if not isinstance(cfg, dict): raise ValidationError( 'Invalid config options for ' 'the "{}" plugin.'.format(name), ) item = name else: cfg = {} if not isinstance(item, str): raise ValidationError('Invalid Plugins configuration') plgins[item] = self.load_plugin(item, cfg) return plgins
def _load_theme_config(self, name): """ Recursively load theme and any parent themes. """ theme_dir = utils.get_theme_dir(name) self.dirs.append(theme_dir) try: file_path = os.path.join(theme_dir, 'mkdocs_theme.yml') with open(file_path, 'rb') as f: theme_config = utils.yaml_load(f) if theme_config is None: theme_config = {} except OSError as e: log.debug(e) raise ValidationError( "The theme '{}' does not appear to have a configuration file. " "Please upgrade to a current version of the theme.".format(name) ) log.debug("Loaded theme configuration for '%s' from '%s': %s", name, file_path, theme_config) parent_theme = theme_config.pop('extends', None) if parent_theme: themes = utils.get_theme_names() if parent_theme not in themes: raise ValidationError( "The theme '{}' inherits from '{}', which does not appear to be installed. " "The available installed themes are: {}".format(name, parent_theme, ', '.join(themes)) ) self._load_theme_config(parent_theme) self.static_templates.update(theme_config.pop('static_templates', [])) self._vars.update(theme_config)
def run_validation(self, value): if value is None: if self.required: raise ValidationError("Required configuration not provided.") else: return () if not isinstance(value, Sequence): raise ValidationError( 'Expected a sequence of mappings, but a %s ' 'was given.' % type(value), ) return [self.item_config.validate(item) for item in value]
def run_validation(self, value): if value == '': return value try: parsed_url = urlparse(value) except (AttributeError, TypeError): raise ValidationError("Unable to parse the URL.") if parsed_url.scheme: return value raise ValidationError( "The URL isn't valid, it should include the http:// (scheme)", )
def run_validation(self, value): if value not in self.choices: msg = ("Expected one of: {} but received: {}".format( self.choices, value)) else: return value raise ValidationError(msg)
def run_validation(self, value): if not isinstance(value, list): raise ValidationError( "Expected a list, got {}".format(type(value)), ) if len(value) == 0: return config_types = {type(item) for item in value} if config_types.issubset({str, dict}): return value raise ValidationError( "Invalid pages config. {} {}".format( config_types, {str, dict}, ), )
def post_validation(self, config, key_name): if config.config_file_path is None: return # Validate that the dir is not the parent dir of the config file. if os.path.dirname(config.config_file_path) == config[key_name]: raise ValidationError( ("The '{0}' should not be the parent directory of the config " "file. Use a child directory instead so that the '{0}' " "is a sibling of the config file.").format(key_name), )
def run_validation(self, value): value = super().run_validation(value) if self.config_dir and not os.path.isabs(value): value = os.path.join(self.config_dir, value) if self.exists and not self.existence_test(value): raise ValidationError( "The path {path} isn't an existing {name}.".format( path=value, name=self.name), ) value = os.path.abspath(value) assert isinstance(value, str) return value
def post_validation(self, config, key_name): super().post_validation(config, key_name) # Validate that the docs_dir and site_dir don't contain the # other as this will lead to copying back and forth on each # and eventually make a deep nested mess. if (config['docs_dir'] + os.sep).startswith(config['site_dir'].rstrip(os.sep) + os.sep): raise ValidationError( ("The 'docs_dir' should not be within the 'site_dir' as this " "can mean the source files are overwritten by the output or " "it will be deleted if --clean is passed to mkdocs build." "(site_dir: '{}', docs_dir: '{}')").format( config['site_dir'], config['docs_dir']), ) elif (config['site_dir'] + os.sep).startswith(config['docs_dir'].rstrip(os.sep) + os.sep): raise ValidationError( ("The 'site_dir' should not be within the 'docs_dir' as this " "leads to the build directory being copied into itself and " "duplicate nested files in the 'site_dir'." "(site_dir: '{}', docs_dir: '{}')").format( config['site_dir'], config['docs_dir']), )
def validate(self, value): if value is None and self.default is not None: value = {'name': self.default} if isinstance(value, str): value = {'name': value} themes = utils.get_theme_names() if isinstance(value, dict): if 'name' in value: if value['name'] is None or value['name'] in themes: return value raise ValidationError( "Unrecognised theme name: '{}'. The available installed themes " "are: {}".format(value['name'], ', '.join(themes)), ) raise ValidationError("No theme name set.") raise ValidationError( 'Invalid type "{}". Expected a string or key/value pairs.'.format( type(value)), )
def run_validation(self, value): try: host, port = value.rsplit(':', 1) except Exception: raise ValidationError("Must be a string of format 'IP:PORT'") if host != 'localhost': try: # Validate and normalize IP Address host = str(ipaddress.ip_address(host)) except ValueError as e: raise ValidationError(e) try: port = int(port) except Exception: raise ValidationError("'{}' is not a valid port".format(port)) class Address(namedtuple('Address', 'host port')): def __str__(self): return '{}:{}'.format(self.host, self.port) return Address(host, port)
def load_plugin(self, name, config): if name not in self.installed_plugins: raise ValidationError( 'The "{}" plugin is not installed'.format(name), ) Plugin = self.installed_plugins[name].load() if not issubclass(Plugin, plugins.BasePlugin): raise ValidationError( '{}.{} must be a subclass of {}.{}'.format( Plugin.__module__, Plugin.__name__, plugins.BasePlugin.__module__, plugins.BasePlugin.__name__, ), ) plugin = Plugin() errors, warnings = plugin.load_config(config, self.config_file_path) self.warnings.extend(warnings) errors_message = '\n'.join( "Plugin value: '{}'. Error: {}".format(x, y) for x, y in errors) if errors_message: raise ValidationError(errors_message) return plugin
def run_validation(self, value): if not isinstance(value, (list, tuple)): raise ValidationError('Invalid Markdown Extensions configuration') extensions = [] for item in value: if isinstance(item, dict): if len(item) > 1: raise ValidationError( 'Invalid Markdown Extensions configuration', ) ext, cfg = item.popitem() extensions.append(ext) if cfg is None: continue if not isinstance(cfg, dict): raise ValidationError( 'Invalid config options for Markdown ' "Extension '{}'.".format(ext), ) self.configdata[ext] = cfg elif isinstance(item, str): extensions.append(item) else: raise ValidationError( 'Invalid Markdown Extensions configuration', ) extensions = utils.reduce_list(self.builtins + extensions) # Confirm that Markdown considers extensions to be valid try: markdown.Markdown( extensions=extensions, extension_configs=self.configdata, ) except Exception as e: raise ValidationError(e.args[0]) return extensions
def post_validation(self, config, key_name): theme_config = config[key_name] if not theme_config['name'] and 'custom_dir' not in theme_config: raise ValidationError( "At least one of 'theme.name' or 'theme.custom_dir' must be defined.", ) # Ensure custom_dir is an absolute path if 'custom_dir' in theme_config and not os.path.isabs( theme_config['custom_dir']): config_dir = os.path.dirname(config.config_file_path) theme_config['custom_dir'] = os.path.join( config_dir, theme_config['custom_dir'], ) if 'custom_dir' in theme_config and not os.path.isdir( theme_config['custom_dir']): raise ValidationError( "The path set in {name}.custom_dir ('{path}') does not exist.". format(path=theme_config['custom_dir'], name=key_name), ) config[key_name] = theme.Theme(**theme_config)
def run_validation(self, value): if not isinstance(value, self._type): msg = ("Expected type: {} but received: {}".format( self._type, type(value))) elif self.length is not None and len(value) != self.length: msg = ("Expected type: {0} with length {2} but received: {1} with " "length {3}").format( self._type, value, self.length, len(value), ) else: return value raise ValidationError(msg)
def validate(self, value): """ Perform some initial validation. If the option is empty (None) and isn't required, leave it as such. If it is empty but has a default, use that. Finally, call the run_validation method on the subclass unless. """ if value is None: if self.default is not None: if hasattr(self.default, 'copy'): # ensure no mutable values are assigned value = self.default.copy() else: value = self.default elif not self.required: return elif self.required: raise ValidationError("Required configuration not provided.") return self.run_validation(value)
def run_validation(self, value): raise ValidationError('For internal use only.')