def create_options_for_optionables(optionables, extra_scopes=None, options=None): """Create a fake Options object for testing with appropriate defaults for the given optionables. Any scoped `options` provided will override defaults, behaving as-if set on the command line. :param iterable optionables: A series of `Optionable` types to register default options for. :param iterable extra_scopes: An optional series of extra known scopes in play. :param dict options: A dict of scope -> (dict of option name -> value) representing option values explicitly set via the command line. :returns: A fake `Options` object with defaults populated for the given `optionables` and any explicitly set `options` overlayed. """ all_options = defaultdict(dict) bootstrap_option_values = None def register_func(on_scope): scoped_options = all_options[on_scope] register = _options_registration_function(scoped_options) register.bootstrap = bootstrap_option_values register.scope = on_scope return register # TODO: This sequence is a bit repetitive of the real registration sequence. # Register bootstrap options and grab their default values for use in subsequent registration. GlobalOptionsRegistrar.register_bootstrap_options(register_func(GLOBAL_SCOPE)) bootstrap_option_values = create_option_values(all_options[GLOBAL_SCOPE].copy()) # Now register the full global scope options. GlobalOptionsRegistrar.register_options(register_func(GLOBAL_SCOPE)) for optionable in optionables: optionable.register_options(register_func(optionable.options_scope)) # Make inner scopes inherit option values from their enclosing scopes. all_scopes = set(all_options.keys()) # TODO(John Sirois): Kill extra scopes one this goes in: # https://github.com/pantsbuild/pants/issues/1957 # For now we need a way for users of this utility to provide extra derived scopes out of band. # With #1957 resolved, the extra scopes will be embedded in the Optionable's option_scope # directly. if extra_scopes: all_scopes.update(extra_scopes) # Iterating in sorted order guarantees that we see outer scopes before inner scopes, # and therefore only have to inherit from our immediately enclosing scope. for s in sorted(all_scopes): if s != GLOBAL_SCOPE: enclosing_scope = s.rpartition(".")[0] opts = all_options[s] for key, val in all_options.get(enclosing_scope, {}).items(): if key not in opts: # Inner scope values override the inherited ones. opts[key] = val if options: for scope, opts in options.items(): all_options[scope].update(opts) return create_options(all_options)
def create_options_for_optionables(optionables, options=None, options_fingerprintable=None, passthru_args=None): """Create a fake Options object for testing with appropriate defaults for the given optionables. Any scoped `options` provided will override defaults, behaving as-if set on the command line. :param iterable optionables: A series of `Optionable` types to register default options for. :param dict options: A dict of scope -> (dict of option name -> value) representing option values explicitly set via the command line. :param dict options_fingerprintable: A dict of scope -> (dict of option name -> option type) representing the fingerprintable options and the scopes they are registered for. :param list passthru_args: A list of passthrough args (specified after `--` on the command line). :returns: A fake `Options` object with defaults populated for the given `optionables` and any explicitly set `options` overlayed. """ all_options = defaultdict(dict) fingerprintable_options = defaultdict(dict) bootstrap_option_values = None if options_fingerprintable: for scope, opts in options_fingerprintable.items(): fingerprintable_options[scope].update(opts) def register_func(on_scope): scoped_options = all_options[on_scope] scoped_fingerprintables = fingerprintable_options[on_scope] register = _options_registration_function(scoped_options, scoped_fingerprintables) register.bootstrap = bootstrap_option_values register.scope = on_scope return register # TODO: This sequence is a bit repetitive of the real registration sequence. # Register bootstrap options and grab their default values for use in subsequent registration. GlobalOptionsRegistrar.register_bootstrap_options( register_func(GLOBAL_SCOPE)) bootstrap_option_values = _FakeOptionValues( all_options[GLOBAL_SCOPE].copy()) # Now register the full global scope options. GlobalOptionsRegistrar.register_options(register_func(GLOBAL_SCOPE)) for optionable in optionables: optionable.register_options(register_func(optionable.options_scope)) if options: for scope, opts in options.items(): all_options[scope].update(opts) return create_options(all_options, passthru_args=passthru_args, fingerprintable_options=fingerprintable_options)
def create_options_for_optionables(optionables, options=None, options_fingerprintable=None, passthru_args=None): """Create a fake Options object for testing with appropriate defaults for the given optionables. Any scoped `options` provided will override defaults, behaving as-if set on the command line. :param iterable optionables: A series of `Optionable` types to register default options for. :param dict options: A dict of scope -> (dict of option name -> value) representing option values explicitly set via the command line. :param dict options_fingerprintable: A dict of scope -> (dict of option name -> option type) representing the fingerprintable options and the scopes they are registered for. :param list passthru_args: A list of passthrough args (specified after `--` on the command line). :returns: A fake `Options` object with defaults populated for the given `optionables` and any explicitly set `options` overlayed. """ all_options = defaultdict(dict) fingerprintable_options = defaultdict(dict) bootstrap_option_values = None if options_fingerprintable: for scope, opts in options_fingerprintable.items(): fingerprintable_options[scope].update(opts) def register_func(on_scope): scoped_options = all_options[on_scope] scoped_fingerprintables = fingerprintable_options[on_scope] register = _options_registration_function(scoped_options, scoped_fingerprintables) register.bootstrap = bootstrap_option_values register.scope = on_scope return register # TODO: This sequence is a bit repetitive of the real registration sequence. # Register bootstrap options and grab their default values for use in subsequent registration. GlobalOptionsRegistrar.register_bootstrap_options(register_func(GLOBAL_SCOPE)) bootstrap_option_values = _FakeOptionValues(all_options[GLOBAL_SCOPE].copy()) # Now register the full global scope options. GlobalOptionsRegistrar.register_options(register_func(GLOBAL_SCOPE)) for optionable in optionables: optionable.register_options(register_func(optionable.options_scope)) if options: for scope, opts in options.items(): all_options[scope].update(opts) return create_options(all_options, passthru_args=passthru_args, fingerprintable_options=fingerprintable_options)
def create_options_for_optionables(optionables, extra_scopes=None, options=None): """Create a fake Options object for testing with appropriate defaults for the given optionables. Any scoped `options` provided will override defaults, behaving as-if set on the command line. :param iterable optionables: A series of `Optionable` types to register default options for. :param iterable extra_scopes: An optional series of extra known scopes in play. :param dict options: A dict of scope -> (dict of option name -> value) representing option values explicitly set via the command line. :returns: A fake `Options` object with defaults populated for the given `optionables` and any explicitly set `options` overlayed. """ all_options = defaultdict(dict) bootstrap_option_values = None def complete_scopes(scopes): """Return all enclosing scopes. This is similar to what `complete_scopes` does in `pants.option.options.Options` without creating `ScopeInfo`s. """ completed_scopes = set(scopes) for scope in scopes: while scope != '': if scope not in completed_scopes: completed_scopes.add(scope) scope = enclosing_scope(scope) return completed_scopes def register_func(on_scope): scoped_options = all_options[on_scope] register = _options_registration_function(scoped_options) register.bootstrap = bootstrap_option_values register.scope = on_scope return register # TODO: This sequence is a bit repetitive of the real registration sequence. # Register bootstrap options and grab their default values for use in subsequent registration. GlobalOptionsRegistrar.register_bootstrap_options( register_func(GLOBAL_SCOPE)) bootstrap_option_values = create_option_values( all_options[GLOBAL_SCOPE].copy()) # Now register the full global scope options. GlobalOptionsRegistrar.register_options(register_func(GLOBAL_SCOPE)) for optionable in optionables: optionable.register_options(register_func(optionable.options_scope)) # Make inner scopes inherit option values from their enclosing scopes. all_scopes = set(all_options.keys()) # TODO(John Sirois): Kill extra scopes one this goes in: # https://github.com/pantsbuild/pants/issues/1957 # For now we need a way for users of this utility to provide extra derived scopes out of band. # With #1957 resolved, the extra scopes will be embedded in the Optionable's option_scope # directly. if extra_scopes: all_scopes.update(extra_scopes) all_scopes = complete_scopes(all_scopes) # Iterating in sorted order guarantees that we see outer scopes before inner scopes, # and therefore only have to inherit from our immediately enclosing scope. for s in sorted(all_scopes): if s != GLOBAL_SCOPE: scope = enclosing_scope(s) opts = all_options[s] for key, val in all_options.get(scope, {}).items(): if key not in opts: # Inner scope values override the inherited ones. opts[key] = val if options: for scope, opts in options.items(): all_options[scope].update(opts) return create_options(all_options)
def context(self, for_task_types=None, options=None, target_roots=None, console_outstream=None, workspace=None): for_task_types = for_task_types or [] options = options or {} option_values = defaultdict(dict) registered_subsystems = set() bootstrap_option_values = None # We fill these in after registering bootstrap options. # We provide our own test-only registration implementation, bypassing argparse. # When testing we set option values directly, so we don't care about cmd-line flags, config, # env vars etc. In fact, for test isolation we explicitly don't want to look at those. # All this does is make the names available in code, with the default values. # Individual tests can then override the option values they care about. def register_func(on_scope): def register(*rargs, **rkwargs): scoped_options = option_values[on_scope] default = rkwargs.get('default') if default is None and rkwargs.get('action') == 'append': default = [] for flag_name in rargs: option_name = flag_name.lstrip('-').replace('-', '_') scoped_options[option_name] = default register.bootstrap = bootstrap_option_values register.scope = on_scope return register # TODO: This sequence is a bit repetitive of the real registration sequence. # Register bootstrap options and grab their default values for use in subsequent registration. GlobalOptionsRegistrar.register_bootstrap_options(register_func(Options.GLOBAL_SCOPE)) bootstrap_option_values = create_option_values(copy.copy(option_values[Options.GLOBAL_SCOPE])) # Now register the full global scope options. GlobalOptionsRegistrar.register_options(register_func(Options.GLOBAL_SCOPE)) # Now register task and subsystem options for relevant tasks. for task_type in for_task_types: scope = task_type.options_scope if scope is None: raise TaskError('You must set a scope on your task type before using it in tests.') task_type.register_options(register_func(scope)) for subsystem in (set(task_type.global_subsystems()) | set(task_type.task_subsystems()) | self._build_configuration.subsystems()): if subsystem not in registered_subsystems: subsystem.register_options(register_func(subsystem.options_scope)) registered_subsystems.add(subsystem) # Now default option values override with any caller-specified values. # TODO(benjy): Get rid of the options arg, and require tests to call set_options. for scope, opts in options.items(): for key, val in opts.items(): option_values[scope][key] = val for scope, opts in self.options.items(): for key, val in opts.items(): option_values[scope][key] = val # Make inner scopes inherit option values from their enclosing scopes. all_scopes = set(option_values.keys()) for task_type in for_task_types: # Make sure we know about pre-task subsystem scopes. all_scopes.update([si.scope for si in task_type.known_scope_infos()]) # Iterating in sorted order guarantees that we see outer scopes before inner scopes, # and therefore only have to inherit from our immediately enclosing scope. for scope in sorted(all_scopes): if scope != Options.GLOBAL_SCOPE: enclosing_scope = scope.rpartition('.')[0] opts = option_values[scope] for key, val in option_values.get(enclosing_scope, {}).items(): if key not in opts: # Inner scope values override the inherited ones. opts[key] = val context = create_context(options=option_values, target_roots=target_roots, build_graph=self.build_graph, build_file_parser=self.build_file_parser, address_mapper=self.address_mapper, console_outstream=console_outstream, workspace=workspace) Subsystem._options = context.options return context
def create_options_for_optionables(optionables, extra_scopes=None, options=None, options_fingerprintable=None, passthru_args=None): """Create a fake Options object for testing with appropriate defaults for the given optionables. Any scoped `options` provided will override defaults, behaving as-if set on the command line. :param iterable optionables: A series of `Optionable` types to register default options for. :param iterable extra_scopes: An optional series of extra known scopes in play. :param dict options: A dict of scope -> (dict of option name -> value) representing option values explicitly set via the command line. :param dict options_fingerprintable: A dict of scope -> (dict of option name -> option type) representing the fingerprintable options and the scopes they are registered for. :param list passthru_args: A list of passthrough args (specified after `--` on the command line). :returns: A fake `Options` object with defaults populated for the given `optionables` and any explicitly set `options` overlayed. """ all_options = defaultdict(dict) fingerprintable_options = defaultdict(dict) bootstrap_option_values = None # NB(cosmicexplorer): we do this again for all_options after calling # register_func below, this is a hack if options: for scope, opts in options.items(): all_options[scope].update(opts) if options_fingerprintable: for scope, opts in options_fingerprintable.items(): fingerprintable_options[scope].update(opts) def complete_scopes(scopes): """Return all enclosing scopes. This is similar to what `complete_scopes` does in `pants.option.options.Options` without creating `ScopeInfo`s. """ completed_scopes = set(scopes) for scope in scopes: while scope != GLOBAL_SCOPE: if scope not in completed_scopes: completed_scopes.add(scope) scope = enclosing_scope(scope) return completed_scopes def register_func(on_scope): scoped_options = all_options[on_scope] scoped_fingerprintables = fingerprintable_options[on_scope] register = _options_registration_function(scoped_options, scoped_fingerprintables) register.bootstrap = bootstrap_option_values register.scope = on_scope return register # TODO: This sequence is a bit repetitive of the real registration sequence. # Register bootstrap options and grab their default values for use in subsequent registration. GlobalOptionsRegistrar.register_bootstrap_options(register_func(GLOBAL_SCOPE)) bootstrap_option_values = _FakeOptionValues(all_options[GLOBAL_SCOPE].copy()) # Now register the full global scope options. GlobalOptionsRegistrar.register_options(register_func(GLOBAL_SCOPE)) for optionable in optionables: optionable.register_options(register_func(optionable.options_scope)) # Make inner scopes inherit option values from their enclosing scopes. all_scopes = set(all_options.keys()) # TODO(John Sirois): Kill extra scopes one this goes in: # https://github.com/pantsbuild/pants/issues/1957 # For now we need a way for users of this utility to provide extra derived scopes out of band. # With #1957 resolved, the extra scopes will be embedded in the Optionable's option_scope # directly. if extra_scopes: all_scopes.update(extra_scopes) all_scopes = complete_scopes(all_scopes) # We need to update options before completing them based on inner/outer relation. if options: for scope, opts in options.items(): all_options[scope].update(opts) # Iterating in sorted order guarantees that we see outer scopes before inner scopes, # and therefore only have to inherit from our immediately enclosing scope. for s in sorted(all_scopes): if s != GLOBAL_SCOPE: scope = enclosing_scope(s) opts = all_options[s] for key, val in all_options.get(scope, {}).items(): if key not in opts: # Inner scope values override the inherited ones. opts[key] = val return create_options(all_options, passthru_args=passthru_args, fingerprintable_options=fingerprintable_options)
def context(self, for_task_types=None, options=None, target_roots=None, console_outstream=None, workspace=None): for_task_types = for_task_types or [] options = options or {} option_values = defaultdict(dict) registered_subsystems = set() bootstrap_option_values = None # We fill these in after registering bootstrap options. # We provide our own test-only registration implementation, bypassing argparse. # When testing we set option values directly, so we don't care about cmd-line flags, config, # env vars etc. In fact, for test isolation we explicitly don't want to look at those. # All this does is make the names available in code, with the default values. # Individual tests can then override the option values they care about. def register_func(on_scope): def register(*rargs, **rkwargs): scoped_options = option_values[on_scope] default = rkwargs.get('default') if default is None and rkwargs.get('action') == 'append': default = [] for flag_name in rargs: option_name = flag_name.lstrip('-').replace('-', '_') scoped_options[option_name] = default register.bootstrap = bootstrap_option_values register.scope = on_scope return register # TODO: This sequence is a bit repetitive of the real registration sequence. # Register bootstrap options and grab their default values for use in subsequent registration. GlobalOptionsRegistrar.register_bootstrap_options( register_func(Options.GLOBAL_SCOPE)) bootstrap_option_values = create_option_values( copy.copy(option_values[Options.GLOBAL_SCOPE])) # Now register the full global scope options. GlobalOptionsRegistrar.register_options( register_func(Options.GLOBAL_SCOPE)) # Now register task and subsystem options for relevant tasks. for task_type in for_task_types: scope = task_type.options_scope if scope is None: raise TaskError( 'You must set a scope on your task type before using it in tests.' ) task_type.register_options(register_func(scope)) for subsystem in (set(task_type.global_subsystems()) | set(task_type.task_subsystems()) | self._build_configuration.subsystems()): if subsystem not in registered_subsystems: subsystem.register_options( register_func(subsystem.options_scope)) registered_subsystems.add(subsystem) # Now default option values override with any caller-specified values. # TODO(benjy): Get rid of the options arg, and require tests to call set_options. for scope, opts in options.items(): for key, val in opts.items(): option_values[scope][key] = val for scope, opts in self.options.items(): for key, val in opts.items(): option_values[scope][key] = val # Make inner scopes inherit option values from their enclosing scopes. all_scopes = set(option_values.keys()) for task_type in for_task_types: # Make sure we know about pre-task subsystem scopes. all_scopes.update( [si.scope for si in task_type.known_scope_infos()]) # Iterating in sorted order guarantees that we see outer scopes before inner scopes, # and therefore only have to inherit from our immediately enclosing scope. for scope in sorted(all_scopes): if scope != Options.GLOBAL_SCOPE: enclosing_scope = scope.rpartition('.')[0] opts = option_values[scope] for key, val in option_values.get(enclosing_scope, {}).items(): if key not in opts: # Inner scope values override the inherited ones. opts[key] = val context = create_context(options=option_values, target_roots=target_roots, build_graph=self.build_graph, build_file_parser=self.build_file_parser, address_mapper=self.address_mapper, console_outstream=console_outstream, workspace=workspace) Subsystem._options = context.options return context