def create(cls, env, config, known_scope_infos, args=None, bootstrap_option_values=None): """Create an Options instance. :param env: a dict of environment variables. :param :class:`pants.option.config.Config` config: data from a config file. :param known_scope_infos: ScopeInfos for all scopes that may be encountered. :param args: a list of cmd-line args; defaults to `sys.argv` if None is supplied. :param bootstrap_option_values: An optional namespace containing the values of bootstrap options. We can use these values when registering other options. """ # We need parsers for all the intermediate scopes, so inherited option values # can propagate through them. complete_known_scope_infos = cls.complete_scopes(known_scope_infos) splitter = ArgSplitter(complete_known_scope_infos) args = sys.argv if args is None else args goals, scope_to_flags, target_specs, passthru, passthru_owner, unknown_scopes = splitter.split_args(args) option_tracker = OptionTracker() if bootstrap_option_values: target_spec_files = bootstrap_option_values.target_spec_files if target_spec_files: for spec in target_spec_files: with open(spec, 'r') as f: target_specs.extend([line for line in [line.strip() for line in f] if line]) help_request = splitter.help_request parser_hierarchy = ParserHierarchy(env, config, complete_known_scope_infos, option_tracker) bootstrap_option_values = bootstrap_option_values known_scope_to_info = {s.scope: s for s in complete_known_scope_infos} return cls(goals, scope_to_flags, target_specs, passthru, passthru_owner, help_request, parser_hierarchy, bootstrap_option_values, known_scope_to_info, option_tracker, unknown_scopes)
def test_env_type_int(self): options = Options.create(env={'PANTS_FOO_BAR': "['123','456']"}, config=self._create_config({}), known_scope_infos=OptionsTest._known_scope_infos, args=shlex.split('./pants'), option_tracker=OptionTracker()) options.register(GLOBAL_SCOPE, '--foo-bar', type=list, member_type=int) self.assertEqual([123, 456], options.for_global_scope().foo_bar) options = Options.create(env={'PANTS_FOO_BAR': '123'}, config=self._create_config({}), known_scope_infos=OptionsTest._known_scope_infos, args=shlex.split('./pants'), option_tracker=OptionTracker()) options.register(GLOBAL_SCOPE, '--foo-bar', type=int) self.assertEqual(123, options.for_global_scope().foo_bar)
def __init__(self, env=None, args=None): self._env = env if env is not None else os.environ.copy() self._post_bootstrap_config = None # Will be set later. self._args = sys.argv if args is None else args self._bootstrap_options = None # We memoize the bootstrap options here. self._full_options = {} # We memoize the full options here. self._option_tracker = OptionTracker()
def create( cls, env: Mapping[str, str], config: Config, known_scope_infos: Iterable[ScopeInfo], args: Optional[Sequence[str]] = None, bootstrap_option_values: Optional[OptionValueContainer] = None, ) -> "Options": """Create an Options instance. :param env: a dict of environment variables. :param config: data from a config file. :param known_scope_infos: ScopeInfos for all scopes that may be encountered. :param args: a list of cmd-line args; defaults to `sys.argv` if None is supplied. :param bootstrap_option_values: An optional namespace containing the values of bootstrap options. We can use these values when registering other options. """ # We need parsers for all the intermediate scopes, so inherited option values # can propagate through them. complete_known_scope_infos = cls.complete_scopes(known_scope_infos) splitter = ArgSplitter(complete_known_scope_infos) args = sys.argv if args is None else args split_args = splitter.split_args(args) if split_args.passthru and len(split_args.goals) > 1: raise cls.AmbiguousPassthroughError( f"Specifying multiple goals (in this case: {split_args.goals}) " "along with passthrough args (args after `--`) is ambiguous.\n" "Try either specifying only a single goal, or passing the passthrough args " "directly to the relevant consumer via its associated flags." ) option_tracker = OptionTracker() if bootstrap_option_values: spec_files = bootstrap_option_values.spec_files if spec_files: for spec_file in spec_files: with open(spec_file, "r") as f: split_args.specs.extend( [line for line in [line.strip() for line in f] if line] ) help_request = splitter.help_request parser_hierarchy = ParserHierarchy(env, config, complete_known_scope_infos, option_tracker) known_scope_to_info = {s.scope: s for s in complete_known_scope_infos} return cls( goals=split_args.goals, scope_to_flags=split_args.scope_to_flags, specs=split_args.specs, passthru=split_args.passthru, help_request=help_request, parser_hierarchy=parser_hierarchy, bootstrap_option_values=bootstrap_option_values, known_scope_to_info=known_scope_to_info, option_tracker=option_tracker, unknown_scopes=split_args.unknown_scopes, )
def test_double_registration(self): options = Options.create(env={}, config=self._create_config({}), known_scope_infos=OptionsTest._known_scope_infos, args=shlex.split('./pants'), option_tracker=OptionTracker()) options.register(GLOBAL_SCOPE, '--foo-bar') self.assertRaises(OptionAlreadyRegistered, lambda: options.register(GLOBAL_SCOPE, '--foo-bar'))
def test_frozen_registration(self): options = Options.create(args=[], env={}, config=self._create_config({}), known_scope_infos=[task('foo')], option_tracker=OptionTracker()) options.register('foo', '--arg1') with self.assertRaises(FrozenRegistration): options.register(GLOBAL_SCOPE, '--arg2')
def assertError(expected_error, *args, **kwargs): with self.assertRaises(expected_error): options = Options.create(args=[], env={}, config=self._create_config({}), known_scope_infos=[], option_tracker=OptionTracker()) options.register(GLOBAL_SCOPE, *args, **kwargs) options.for_global_scope()
def _parse(self, args_str, env=None, config=None, bootstrap_option_values=None): args = shlex.split(str(args_str)) options = Options.create(env=env or {}, config=self._create_config(config or {}), known_scope_infos=OptionsTest._known_scope_infos, args=args, bootstrap_option_values=bootstrap_option_values, option_tracker=OptionTracker()) self._register(options) return options
def test_deprecated_option_past_removal(self): with self.assertRaises(PastRemovalVersionError): options = Options.create(env={}, config=self._create_config({}), known_scope_infos=OptionsTest._known_scope_infos, args='./pants', option_tracker=OptionTracker()) options.register(GLOBAL_SCOPE, '--too-old-option', deprecated_version='0.0.24', deprecated_hint='The semver for this option has already passed.') options.for_global_scope()
def _parse_type_int(self, args_str, env=None, config=None, bootstrap_option_values=None, action=None): args = shlex.split(str(args_str)) options = Options.create(env=env or {}, config=self._create_config(config or {}), known_scope_infos=OptionsTest._known_scope_infos, args=args, bootstrap_option_values=bootstrap_option_values, option_tracker=OptionTracker()) options.register(GLOBAL_SCOPE, '--config-override', action=action, type=int) return options
def do_test(args, kwargs, expected_default): # Defaults are computed in the parser and added into the kwargs, so we # must jump through this hoop in this test. parser = Parser(env={}, config=Config.load([]), scope_info=GlobalOptionsRegistrar.get_scope_info(), parent_parser=None, option_tracker=OptionTracker()) parser.register(*args, **kwargs) oshi = HelpInfoExtracter.get_option_scope_help_info_from_parser(parser).basic self.assertEquals(1, len(oshi)) ohi = oshi[0] self.assertEqual(expected_default, ohi.default)
def test_no_recursive_subsystem_options(self): options = Options.create(env={}, config=self._create_config({}), known_scope_infos=[subsystem('foo')], args='./pants', option_tracker=OptionTracker()) # All subsystem options are implicitly recursive (a subscope of subsystem scope represents # a separate instance of the subsystem, so it needs all the options). # We disallow explicit specification of recursive (even if set to True), to avoid confusion. with self.assertRaises(RecursiveSubsystemOption): options.register('foo', '--bar', recursive=False) options.for_scope('foo') with self.assertRaises(RecursiveSubsystemOption): options.register('foo', '--baz', recursive=True) options.for_scope('foo')
def test_shadowing(self): options = Options.create(env={}, config=self._create_config({}), known_scope_infos=[task('bar'), intermediate('foo'), task('foo.bar')], args='./pants', option_tracker=OptionTracker()) options.register('', '--opt1') options.register('foo', '-o', '--opt2') with self.assertRaises(Shadowing): options.register('bar', '--opt1') with self.assertRaises(Shadowing): options.register('foo.bar', '--opt1') with self.assertRaises(Shadowing): options.register('foo.bar', '--opt2') with self.assertRaises(Shadowing): options.register('foo.bar', '--opt1', '--opt3') with self.assertRaises(Shadowing): options.register('foo.bar', '--opt3', '--opt2')