示例#1
0
 def _finalize(self):
     """ Finalize the value of any options that require that
     additional post-processing step.  (Mostly
     :class:`Bcfg2.Options.Actions.ComponentAction` subclasses.)
     """
     _debug("Finalizing options")
     for opt in self.option_list[:]:
         opt.finalize(self.namespace)
示例#2
0
    def shutdown(self):
        """Perform shutdown tasks.

        This calls the ``shutdown`` method of the subcommand that was
        run.
        """
        _debug("Shutting down subcommand %s" % master_setup.subcommand)
        self.commands[master_setup.subcommand].shutdown()
示例#3
0
文件: Parser.py 项目: Bcfg2/bcfg2
 def add_component(self, component):
     """ Add a component (and all of its options) to the
     parser. """
     if component not in self.components:
         _debug("Adding component %s to %s" % (component, self))
         self.components.append(component)
         if hasattr(component, "options"):
             self.add_options(getattr(component, "options"))
示例#4
0
文件: Parser.py 项目: Bcfg2/bcfg2
 def _finalize(self):
     """ Finalize the value of any options that require that
     additional post-processing step.  (Mostly
     :class:`Bcfg2.Options.Actions.ComponentAction` subclasses.)
     """
     _debug("Finalizing options")
     for opt in self.option_list[:]:
         opt.finalize(self.namespace)
示例#5
0
    def shutdown(self):
        """Perform shutdown tasks.

        This calls the ``shutdown`` method of the subcommand that was
        run.
        """
        _debug("Shutting down subcommand %s" % master_setup.subcommand)
        self.commands[master_setup.subcommand].shutdown()
示例#6
0
 def add_component(self, component):
     """ Add a component (and all of its options) to the
     parser. """
     if component not in self.components:
         _debug("Adding component %s to %s" % (component, self))
         self.components.append(component)
         if hasattr(component, "options"):
             self.add_options(getattr(component, "options"))
示例#7
0
文件: Parser.py 项目: Bcfg2/bcfg2
 def _set_defaults_from_config(self):
     """ Set defaults from the config file for all options that can
     come from the config file, but haven't yet had their default
     set """
     _debug("Setting defaults on all options")
     for opt in self.option_list:
         if opt not in self._defaults_set:
             opt.default_from_config(self._cfp)
             self._defaults_set.append(opt)
示例#8
0
 def _set_defaults_from_config(self):
     """ Set defaults from the config file for all options that can
     come from the config file, but haven't yet had their default
     set """
     _debug("Setting defaults on all options")
     for opt in self.option_list:
         if opt not in self._defaults_set:
             opt.default_from_config(self._cfp)
             self._defaults_set.append(opt)
示例#9
0
 def runcommand(self):
     """ Run the single command named in
     ``Bcfg2.Options.setup.subcommand``, which is where
     :class:`Bcfg2.Options.Subparser` groups store the
     subcommand. """
     _debug("Running subcommand %s" % master_setup.subcommand)
     try:
         return self.commands[master_setup.subcommand].run(master_setup)
     finally:
         self.shutdown()
示例#10
0
 def runcommand(self):
     """ Run the single command named in
     ``Bcfg2.Options.setup.subcommand``, which is where
     :class:`Bcfg2.Options.Subparser` groups store the
     subcommand. """
     _debug("Running subcommand %s" % master_setup.subcommand)
     try:
         return self.commands[master_setup.subcommand].run(master_setup)
     finally:
         self.shutdown()
示例#11
0
    def reparse(self, argv=None):
        """ Reparse options after they have already been parsed.

        :param argv: The argument list to parse.  By default,
                     :attr:`Bcfg2.Options.Parser.argv` is reused.
                     (I.e., the argument list that was initially
                     parsed.)  :type argv: list
        """
        _debug("Reparsing all options")
        self._reset_namespace()
        self.parse(argv or self.argv)
示例#12
0
文件: Parser.py 项目: Bcfg2/bcfg2
 def _reset_namespace(self):
     """ Delete all options from the namespace except for a few
     predefined values and config file options. """
     self.parsed = False
     _debug("Resetting namespace")
     for attr in dir(self.namespace):
         if (not attr.startswith("_") and
                 attr not in ['uri', 'version', 'name'] and
                 attr not in self._config_files):
             _debug("Deleting %s" % attr)
             delattr(self.namespace, attr)
示例#13
0
    def reparse(self, argv=None):
        """ Reparse options after they have already been parsed.

        :param argv: The argument list to parse.  By default,
                     :attr:`Bcfg2.Options.Parser.argv` is reused.
                     (I.e., the argument list that was initially
                     parsed.)  :type argv: list
        """
        _debug("Reparsing all options")
        self._reset_namespace()
        self.parse(argv or self.argv)
示例#14
0
 def _reset_namespace(self):
     """ Delete all options from the namespace except for a few
     predefined values and config file options. """
     self.parsed = False
     _debug("Resetting namespace")
     for attr in dir(self.namespace):
         if (not attr.startswith("_")
                 and attr not in ['uri', 'version', 'name']
                 and attr not in self._config_files):
             _debug("Deleting %s" % attr)
             delattr(self.namespace, attr)
示例#15
0
 def add_config_file(self, dest, cfile, reparse=True):
     """ Add a config file, which triggers a full reparse of all
     options. """
     if dest not in self._config_files:
         _debug("Adding new config file %s for %s" % (cfile, dest))
         self._reset_namespace()
         self._cfp.read([cfile])
         self._defaults_set = []
         self._set_defaults_from_config()
         if reparse:
             self._parse_config_options()
         self._config_files.append(dest)
示例#16
0
文件: Parser.py 项目: Bcfg2/bcfg2
 def add_config_file(self, dest, cfile, reparse=True):
     """ Add a config file, which triggers a full reparse of all
     options. """
     if dest not in self._config_files:
         _debug("Adding new config file %s for %s" % (cfile, dest))
         self._reset_namespace()
         self._cfp.read([cfile])
         self._defaults_set = []
         self._set_defaults_from_config()
         if reparse:
             self._parse_config_options()
         self._config_files.append(dest)
示例#17
0
 def _parse_config_options(self):
     """ populate the namespace with default values for any options
     that aren't already in the namespace (i.e., options without
     CLI arguments) """
     _debug("Parsing config file-only options")
     for opt in self.option_list[:]:
         if not opt.args and opt.dest not in self.namespace:
             value = opt.default
             if value:
                 for _, action in opt.actions.items():
                     _debug("Setting config file-only option %s to %s" %
                            (opt, value))
                     action(self, self.namespace, value)
             else:
                 setattr(self.namespace, opt.dest, value)
示例#18
0
 def _parse_config_options(self):
     """ populate the namespace with default values for any options
     that aren't already in the namespace (i.e., options without
     CLI arguments) """
     _debug("Parsing config file-only options")
     for opt in self.option_list[:]:
         if not opt.args and opt.dest not in self.namespace:
             value = opt.default
             if value:
                 for _, action in opt.actions.items():
                     _debug("Setting config file-only option %s to %s" %
                            (opt, value))
                     action(self, self.namespace, value)
             else:
                 setattr(self.namespace, opt.dest, value)
示例#19
0
文件: Parser.py 项目: xschlef/bcfg2
    def _parse_early_options(self):
        """Parse early options.

        Early options are options that need to be parsed before other
        options for some reason. These fall into two basic cases:

        1. Database options, which need to be parsed so that Django
           modules can be imported, since Django configuration is all
           done at import-time;
        2. The repository (``-Q``) option, so that ``<repository>``
           macros in other options can be resolved.
        """
        _debug("Option parsing phase 2: Parse early options")
        early_opts = argparse.Namespace()
        early_parser = Parser(add_help=False, namespace=early_opts,
                              early=True)

        # add the repo option so we can resolve <repository>
        # macros
        early_parser.add_options([repository])

        early_components = []
        for component in self.components:
            if getattr(component, "parse_first", False):
                early_components.append(component)
                early_parser.add_component(component)
        early_parser.parse(self.argv)

        _debug("Fixing up <repository> macros in early options")
        for attr_name in dir(early_opts):
            if not attr_name.startswith("_"):
                attr = getattr(early_opts, attr_name)
                if hasattr(attr, "replace"):
                    setattr(early_opts, attr_name,
                            attr.replace("<repository>",
                                         early_opts.repository))

        _debug("Early parsing complete, calling hooks")
        for component in early_components:
            if hasattr(component, "component_parsed_hook"):
                _debug("Calling component_parsed_hook on %s" % component)
                getattr(component, "component_parsed_hook")(early_opts)
        _debug("Calling early parsing hooks; early options: %s" %
               early_opts)
        for option in self.option_list:
            option.early_parsing_hook(early_opts)
示例#20
0
    def early_parsing_hook(self, namespace):
        """
        We want a usefull default for the enabled lint plugins.
        Therfore we use all importable plugins, that either pertain
        with enabled server plugins or that has no matching plugin.
        """

        plugins = [p.__name__ for p in namespace.plugins]
        for loader, name, _is_pkg in walk_packages(path=__path__):
            try:
                module = loader.find_module(name).load_module(name)
                plugin = getattr(module, name)
                if plugin.__serverplugin__ is None or \
                   plugin.__serverplugin__ in plugins:
                    _debug("Automatically adding lint plugin %s" %
                           plugin.__name__)
                    self.default.append(plugin.__name__)
            except ImportError:
                pass
示例#21
0
文件: __init__.py 项目: xschlef/bcfg2
    def early_parsing_hook(self, namespace):
        """
        We want a usefull default for the enabled lint plugins.
        Therfore we use all importable plugins, that either pertain
        with enabled server plugins or that has no matching plugin.
        """

        plugins = [p.__name__ for p in namespace.plugins]
        for loader, name, _is_pkg in walk_packages(path=__path__):
            try:
                module = loader.find_module(name).load_module(name)
                plugin = getattr(module, name)
                if plugin.__serverplugin__ is None or \
                   plugin.__serverplugin__ in plugins:
                    _debug("Automatically adding lint plugin %s" %
                           plugin.__name__)
                    self.default.append(plugin.__name__)
            except ImportError:
                pass
示例#22
0
文件: Parser.py 项目: Ank2015/bcfg2
    def add_options(self, options):
        """ Add an explicit list of options to the parser.  When
        possible, prefer :func:`Bcfg2.Options.Parser.add_component` to
        add a whole component instead."""
        _debug("Adding options: %s" % options)
        self.parsed = False
        for option in options:
            if option not in self.option_list:
                # check for duplicates
                if (hasattr(option, "env") and option.env and
                        option.env in [o.env for o in self.option_list]):
                    raise OptionParserException(
                        "Duplicate environment variable option: %s" %
                        option.env)
                if (hasattr(option, "cf") and option.cf and
                        option.cf in [o.cf for o in self.option_list]):
                    raise OptionParserException(
                        "Duplicate config file option: %s" % (option.cf,))

                self.option_list.extend(option.list_options())
                option.add_to_parser(self)
示例#23
0
    def add_options(self, options):
        """ Add an explicit list of options to the parser.  When
        possible, prefer :func:`Bcfg2.Options.Parser.add_component` to
        add a whole component instead."""
        _debug("Adding options: %s" % options)
        self.parsed = False
        for option in options:
            if option not in self.option_list:
                # check for duplicates
                if (hasattr(option, "env") and option.env
                        and option.env in [o.env for o in self.option_list]):
                    raise OptionParserException(
                        "Duplicate environment variable option: %s" %
                        option.env)
                if (hasattr(option, "cf") and option.cf
                        and option.cf in [o.cf for o in self.option_list]):
                    raise OptionParserException(
                        "Duplicate config file option: %s" % (option.cf, ))

                self.option_list.extend(option.list_options())
                option.add_to_parser(self)
                for opt in option.list_options():
                    opt.default_from_config(self._cfp)
                    self._defaults_set.append(opt)
示例#24
0
    def parse(self, argv=None):
        """ Parse options.

        :param argv: The argument list to parse.  By default,
                     ``sys.argv[1:]`` is used.  This is stored in
                     :attr:`Bcfg2.Options.Parser.argv` for reuse by
                     :func:`Bcfg2.Options.Parser.reparse`.
        :type argv: list
        """
        _debug("Parsing options")
        if argv is None:
            argv = sys.argv[1:]  # pragma: nocover
        if self.parsed and self.argv == argv:
            _debug("Returning already parsed namespace")
            return self.namespace
        self.argv = argv

        # phase 1: get and read config file
        _debug("Option parsing phase 1: Get and read main config file")
        bootstrap_parser = argparse.ArgumentParser(add_help=False)
        self.configfile.add_to_parser(bootstrap_parser)
        self.configfile.default_from_config(self._cfp)
        bootstrap = bootstrap_parser.parse_known_args(args=self.argv)[0]

        # check whether the specified bcfg2.conf exists
        if not self.unit_test and not os.path.exists(bootstrap.config):
            sys.stderr.write("Could not read %s\n" % bootstrap.config)
        self.add_config_file(self.configfile.dest,
                             bootstrap.config,
                             reparse=False)

        # phase 2: re-parse command line for early options; currently,
        # that's database options
        if not self._early:
            self._parse_early_options()
        else:
            _debug("Skipping parsing phase 2 in early mode")

        # phase 3: re-parse command line, loading additional
        # components, until all components have been loaded.  On each
        # iteration, set defaults from config file/environment
        # variables
        _debug("Option parsing phase 3: Main parser loop")
        # _set_defaults_from_config must be called before _parse_config_options
        # This is due to a tricky interaction between the two methods:
        #
        # (1) _set_defaults_from_config does what its name implies, it updates
        # the "default" property of each Option based on the value that exists
        # in the config.
        #
        # (2)  _parse_config_options will look at each option and set it to the
        # default value that is _currently_ defined.  If the option does not
        # exist in the namespace, it will be added.  The method carefully
        # avoids overwriting the value of an option that is already defined in
        # the namespace.
        #
        # Thus, if _set_defaults_from_config has not been called yet when
        # _parse_config_options is called, all config file options will get set
        # to their hardcoded defaults.  This process defines the options in the
        # namespace and _parse_config_options will never look at them again.
        #
        # we have to do the parsing in two loops: first, we squeeze as
        # much data out of the config file as we can to ensure that
        # all config file settings are read before we use any default
        # values. then we can start looking at the command line.
        while not self.parsed:
            self.parsed = True
            self._set_defaults_from_config()
            self._parse_config_options()
        self.parsed = False
        remaining = []
        while not self.parsed:
            self.parsed = True
            _debug("Parsing known arguments")
            try:
                _, remaining = self.parse_known_args(args=self.argv,
                                                     namespace=self.namespace)
            except OptionParserException:
                self.error(sys.exc_info()[1])
            self._set_defaults_from_config()
            self._parse_config_options()
            self._finalize()
        if len(remaining) and not self._early:
            self.error("Unknown options: %s" % " ".join(remaining))

        # phase 4: call post-parsing hooks
        if not self._early:
            _debug("Option parsing phase 4: Call hooks")
            for component in self.components:
                if hasattr(component, "options_parsed_hook"):
                    _debug("Calling post-parsing hook on %s" % component)
                    getattr(component, "options_parsed_hook")()

        return self.namespace
示例#25
0
    def parse(self, argv=None):
        """ Parse options.

        :param argv: The argument list to parse.  By default,
                     ``sys.argv[1:]`` is used.  This is stored in
                     :attr:`Bcfg2.Options.Parser.argv` for reuse by
                     :func:`Bcfg2.Options.Parser.reparse`.
        :type argv: list
        """
        _debug("Parsing options")
        if argv is None:
            argv = sys.argv[1:]
        if self.parsed and self.argv == argv:
            _debug("Returning already parsed namespace")
            return self.namespace
        self.argv = argv

        # phase 1: get and read config file
        _debug("Option parsing phase 1: Get and read main config file")
        bootstrap_parser = argparse.ArgumentParser(add_help=False)
        self.configfile.add_to_parser(bootstrap_parser)
        self.configfile.default_from_config(self._cfp)
        bootstrap = bootstrap_parser.parse_known_args(args=self.argv)[0]

        # check whether the specified bcfg2.conf exists
        if not self.unit_test and not os.path.exists(bootstrap.config):
            self.error("Could not read %s" % bootstrap.config)
        self.add_config_file(self.configfile.dest,
                             bootstrap.config,
                             reparse=False)

        # phase 2: re-parse command line for early options; currently,
        # that's database options
        _debug("Option parsing phase 2: Parse early options")
        if not self._early:
            early_opts = argparse.Namespace()
            early_parser = Parser(add_help=False,
                                  namespace=early_opts,
                                  early=True)
            # add the repo option so we can resolve <repository>
            # macros
            early_parser.add_options([repository])
            early_components = []
            for component in self.components:
                if getattr(component, "parse_first", False):
                    early_components.append(component)
                    early_parser.add_component(component)
            early_parser.parse(self.argv)
            _debug("Early parsing complete, calling hooks")
            for component in early_components:
                if hasattr(component, "component_parsed_hook"):
                    _debug("Calling component_parsed_hook on %s" % component)
                    getattr(component, "component_parsed_hook")(early_opts)

        # phase 3: re-parse command line, loading additional
        # components, until all components have been loaded.  On each
        # iteration, set defaults from config file/environment
        # variables
        _debug("Option parsing phase 3: Main parser loop")
        # _set_defaults_from_config must be called before _parse_config_options
        # This is due to a tricky interaction between the two methods:
        #
        # (1) _set_defaults_from_config does what its name implies, it updates
        # the "default" property of each Option based on the value that exists
        # in the config.
        #
        # (2)  _parse_config_options will look at each option and set it to the
        # default value that is _currently_ defined.  If the option does not
        # exist in the namespace, it will be added.  The method carefully
        # avoids overwriting the value of an option that is already defined in
        # the namespace.
        #
        # Thus, if _set_defaults_from_config has not been called yet when
        # _parse_config_options is called, all config file options will get set
        # to their hardcoded defaults.  This process defines the options in the
        # namespace and _parse_config_options will never look at them again.
        self._set_defaults_from_config()
        self._parse_config_options()
        while not self.parsed:
            self.parsed = True
            self._set_defaults_from_config()
            self.parse_known_args(args=self.argv, namespace=self.namespace)
            self._parse_config_options()
            self._finalize()

        # phase 4: fix up <repository> macros
        _debug("Option parsing phase 4: Fix up macros")
        repo = getattr(self.namespace, "repository", repository.default)
        for attr in dir(self.namespace):
            value = getattr(self.namespace, attr)
            if (not attr.startswith("_") and hasattr(value, "replace")
                    and "<repository>" in value):
                setattr(self.namespace, attr,
                        value.replace("<repository>", repo, 1))
                _debug("Fixing up macros in %s: %s -> %s" %
                       (attr, value, getattr(self.namespace, attr)))

        # phase 5: call post-parsing hooks
        _debug("Option parsing phase 5: Call hooks")
        if not self._early:
            for component in self.components:
                if hasattr(component, "options_parsed_hook"):
                    _debug("Calling post-parsing hook on %s" % component)
                    getattr(component, "options_parsed_hook")()

        return self.namespace
示例#26
0
    def parse(self, argv=None):
        """ Parse options.

        :param argv: The argument list to parse.  By default,
                     ``sys.argv[1:]`` is used.  This is stored in
                     :attr:`Bcfg2.Options.Parser.argv` for reuse by
                     :func:`Bcfg2.Options.Parser.reparse`.
        :type argv: list
        """
        _debug("Parsing options")
        if argv is None:
            argv = sys.argv[1:]
        if self.parsed and self.argv == argv:
            _debug("Returning already parsed namespace")
            return self.namespace
        self.argv = argv

        # phase 1: get and read config file
        _debug("Option parsing phase 1: Get and read main config file")
        bootstrap_parser = argparse.ArgumentParser(add_help=False)
        self.configfile.add_to_parser(bootstrap_parser)
        self.configfile.default_from_config(self._cfp)
        bootstrap = bootstrap_parser.parse_known_args(args=self.argv)[0]

        # check whether the specified bcfg2.conf exists
        if not self.unit_test and not os.path.exists(bootstrap.config):
            self.error("Could not read %s" % bootstrap.config)
        self.add_config_file(self.configfile.dest, bootstrap.config,
                             reparse=False)

        # phase 2: re-parse command line for early options; currently,
        # that's database options
        _debug("Option parsing phase 2: Parse early options")
        if not self._early:
            early_opts = argparse.Namespace()
            early_parser = Parser(add_help=False, namespace=early_opts,
                                  early=True)
            # add the repo option so we can resolve <repository>
            # macros
            early_parser.add_options([repository])
            early_components = []
            for component in self.components:
                if getattr(component, "parse_first", False):
                    early_components.append(component)
                    early_parser.add_component(component)
            early_parser.parse(self.argv)
            _debug("Early parsing complete, calling hooks")
            for component in early_components:
                if hasattr(component, "component_parsed_hook"):
                    _debug("Calling component_parsed_hook on %s" % component)
                    getattr(component, "component_parsed_hook")(early_opts)

        # phase 3: re-parse command line, loading additional
        # components, until all components have been loaded.  On each
        # iteration, set defaults from config file/environment
        # variables
        _debug("Option parsing phase 3: Main parser loop")
        # _set_defaults_from_config must be called before _parse_config_options
        # This is due to a tricky interaction between the two methods:
        #
        # (1) _set_defaults_from_config does what its name implies, it updates
        # the "default" property of each Option based on the value that exists
        # in the config.
        #
        # (2)  _parse_config_options will look at each option and set it to the
        # default value that is _currently_ defined.  If the option does not
        # exist in the namespace, it will be added.  The method carefully
        # avoids overwriting the value of an option that is already defined in
        # the namespace.
        #
        # Thus, if _set_defaults_from_config has not been called yet when
        # _parse_config_options is called, all config file options will get set
        # to their hardcoded defaults.  This process defines the options in the
        # namespace and _parse_config_options will never look at them again.
        self._set_defaults_from_config()
        self._parse_config_options()
        while not self.parsed:
            self.parsed = True
            self._set_defaults_from_config()
            self.parse_known_args(args=self.argv, namespace=self.namespace)
            self._parse_config_options()
            self._finalize()

        # phase 4: fix up <repository> macros
        _debug("Option parsing phase 4: Fix up macros")
        repo = getattr(self.namespace, "repository", repository.default)
        for attr in dir(self.namespace):
            value = getattr(self.namespace, attr)
            if (not attr.startswith("_") and
                hasattr(value, "replace") and
                "<repository>" in value):
                setattr(self.namespace, attr,
                        value.replace("<repository>", repo, 1))
                _debug("Fixing up macros in %s: %s -> %s" %
                       (attr, value, getattr(self.namespace, attr)))

        # phase 5: call post-parsing hooks
        _debug("Option parsing phase 5: Call hooks")
        if not self._early:
            for component in self.components:
                if hasattr(component, "options_parsed_hook"):
                    _debug("Calling post-parsing hook on %s" % component)
                    getattr(component, "options_parsed_hook")()

        return self.namespace
示例#27
0
文件: Parser.py 项目: Bcfg2/bcfg2
    def parse(self, argv=None):
        """ Parse options.

        :param argv: The argument list to parse.  By default,
                     ``sys.argv[1:]`` is used.  This is stored in
                     :attr:`Bcfg2.Options.Parser.argv` for reuse by
                     :func:`Bcfg2.Options.Parser.reparse`.
        :type argv: list
        """
        _debug("Parsing options")
        if argv is None:
            argv = sys.argv[1:]  # pragma: nocover
        if self.parsed and self.argv == argv:
            _debug("Returning already parsed namespace")
            return self.namespace
        self.argv = argv

        # phase 1: get and read config file
        _debug("Option parsing phase 1: Get and read main config file")
        bootstrap_parser = argparse.ArgumentParser(add_help=False)
        self.configfile.add_to_parser(bootstrap_parser)
        self.configfile.default_from_config(self._cfp)
        bootstrap = bootstrap_parser.parse_known_args(args=self.argv)[0]

        # check whether the specified bcfg2.conf exists
        if not self.unit_test and not os.path.exists(bootstrap.config):
            sys.stderr.write("Could not read %s\n" % bootstrap.config)
        self.add_config_file(self.configfile.dest, bootstrap.config,
                             reparse=False)

        # phase 2: re-parse command line for early options; currently,
        # that's database options
        if not self._early:
            self._parse_early_options()
        else:
            _debug("Skipping parsing phase 2 in early mode")

        # phase 3: re-parse command line, loading additional
        # components, until all components have been loaded.  On each
        # iteration, set defaults from config file/environment
        # variables
        _debug("Option parsing phase 3: Main parser loop")
        # _set_defaults_from_config must be called before _parse_config_options
        # This is due to a tricky interaction between the two methods:
        #
        # (1) _set_defaults_from_config does what its name implies, it updates
        # the "default" property of each Option based on the value that exists
        # in the config.
        #
        # (2)  _parse_config_options will look at each option and set it to the
        # default value that is _currently_ defined.  If the option does not
        # exist in the namespace, it will be added.  The method carefully
        # avoids overwriting the value of an option that is already defined in
        # the namespace.
        #
        # Thus, if _set_defaults_from_config has not been called yet when
        # _parse_config_options is called, all config file options will get set
        # to their hardcoded defaults.  This process defines the options in the
        # namespace and _parse_config_options will never look at them again.
        #
        # we have to do the parsing in two loops: first, we squeeze as
        # much data out of the config file as we can to ensure that
        # all config file settings are read before we use any default
        # values. then we can start looking at the command line.
        while not self.parsed:
            self.parsed = True
            self._set_defaults_from_config()
            self._parse_config_options()
        self.parsed = False
        remaining = []
        while not self.parsed:
            self.parsed = True
            _debug("Parsing known arguments")
            try:
                _, remaining = self.parse_known_args(args=self.argv,
                                                     namespace=self.namespace)
            except OptionParserException:
                self.error(sys.exc_info()[1])
            self._set_defaults_from_config()
            self._parse_config_options()
            self._finalize()
        if len(remaining) and not self._early:
            self.error("Unknown options: %s" % " ".join(remaining))

        # phase 4: call post-parsing hooks
        if not self._early:
            _debug("Option parsing phase 4: Call hooks")
            for component in self.components:
                if hasattr(component, "options_parsed_hook"):
                    _debug("Calling post-parsing hook on %s" % component)
                    getattr(component, "options_parsed_hook")()

        return self.namespace