%PDF- %PDF-
Direktori : /proc/thread-self/root/lib/python3/dist-packages/mkdocs/config/ |
Current File : //proc/thread-self/root/lib/python3/dist-packages/mkdocs/config/base.py |
import logging import os import sys from yaml import YAMLError from collections import UserDict from mkdocs import exceptions from mkdocs import utils log = logging.getLogger('mkdocs.config') class ValidationError(Exception): """Raised during the validation process of the config on errors.""" class Config(UserDict): """ MkDocs Configuration dict This is a fairly simple extension of a standard dictionary. It adds methods for running validation on the structure and contents. """ def __init__(self, schema, config_file_path=None): """ The schema is a Python dict which maps the config name to a validator. """ self._schema = schema self._schema_keys = set(dict(schema).keys()) # Ensure config_file_path is a Unicode string if config_file_path is not None and not isinstance(config_file_path, str): try: # Assume config_file_path is encoded with the file system encoding. config_file_path = config_file_path.decode(encoding=sys.getfilesystemencoding()) except UnicodeDecodeError: raise ValidationError("config_file_path is not a Unicode string.") self.config_file_path = config_file_path self.data = {} self.user_configs = [] self.set_defaults() def set_defaults(self): """ Set the base config by going through each validator and getting the default if it has one. """ for key, config_option in self._schema: self[key] = config_option.default def _validate(self): failed, warnings = [], [] for key, config_option in self._schema: try: value = self.get(key) self[key] = config_option.validate(value) warnings.extend([(key, w) for w in config_option.warnings]) config_option.reset_warnings() except ValidationError as e: failed.append((key, e)) for key in (set(self.keys()) - self._schema_keys): warnings.append(( key, "Unrecognised configuration name: {}".format(key) )) return failed, warnings def _pre_validate(self): failed, warnings = [], [] for key, config_option in self._schema: try: config_option.pre_validation(self, key_name=key) warnings.extend([(key, w) for w in config_option.warnings]) config_option.reset_warnings() except ValidationError as e: failed.append((key, e)) return failed, warnings def _post_validate(self): failed, warnings = [], [] for key, config_option in self._schema: try: config_option.post_validation(self, key_name=key) warnings.extend([(key, w) for w in config_option.warnings]) config_option.reset_warnings() except ValidationError as e: failed.append((key, e)) return failed, warnings def validate(self): failed, warnings = self._pre_validate() run_failed, run_warnings = self._validate() failed.extend(run_failed) warnings.extend(run_warnings) # Only run the post validation steps if there are no failures, warnings # are okay. if len(failed) == 0: post_failed, post_warnings = self._post_validate() failed.extend(post_failed) warnings.extend(post_warnings) return failed, warnings def load_dict(self, patch): if not isinstance(patch, dict): raise exceptions.ConfigurationError( "The configuration is invalid. The expected type was a key " "value mapping (a python dict) but we got an object of type: " "{}".format(type(patch))) self.user_configs.append(patch) self.data.update(patch) def load_file(self, config_file): try: return self.load_dict(utils.yaml_load(config_file)) except YAMLError as e: # MkDocs knows and understands ConfigurationErrors raise exceptions.ConfigurationError( "MkDocs encountered as error parsing the configuration file: {}".format(e) ) def _open_config_file(config_file): # Default to the standard config filename. if config_file is None: config_file = os.path.abspath('mkdocs.yml') # If closed file descriptor, get file path to reopen later. if hasattr(config_file, 'closed') and config_file.closed: config_file = config_file.name log.debug("Loading configuration file: {}".format(config_file)) # If it is a string, we can assume it is a path and attempt to open it. if isinstance(config_file, str): if os.path.exists(config_file): config_file = open(config_file, 'rb') else: raise exceptions.ConfigurationError( "Config file '{}' does not exist.".format(config_file)) # Ensure file descriptor is at begining config_file.seek(0) return config_file def load_config(config_file=None, **kwargs): """ Load the configuration for a given file object or name The config_file can either be a file object, string or None. If it is None the default `mkdocs.yml` filename will loaded. Extra kwargs are passed to the configuration to replace any default values unless they themselves are None. """ options = kwargs.copy() # Filter None values from the options. This usually happens with optional # parameters from Click. for key, value in options.copy().items(): if value is None: options.pop(key) config_file = _open_config_file(config_file) options['config_file_path'] = getattr(config_file, 'name', '') # Initialise the config with the default schema . from mkdocs import config cfg = Config(schema=config.DEFAULT_SCHEMA, config_file_path=options['config_file_path']) # First load the config file cfg.load_file(config_file) # Then load the options to overwrite anything in the config. cfg.load_dict(options) errors, warnings = cfg.validate() for config_name, warning in warnings: log.warning("Config value: '%s'. Warning: %s", config_name, warning) for config_name, error in errors: log.error("Config value: '%s'. Error: %s", config_name, error) for key, value in cfg.items(): log.debug("Config value: '%s' = %r", key, value) if len(errors) > 0: raise exceptions.ConfigurationError( "Aborted with {} Configuration Errors!".format(len(errors)) ) elif cfg['strict'] and len(warnings) > 0: raise exceptions.ConfigurationError( "Aborted with {} Configuration Warnings in 'strict' mode!".format(len(warnings)) ) return cfg