def test_private_without_default(self): def main(_a: int): assert False with self.assertRaisesRegex(ValueError, # Older Pythons have no space post-colon. r'Parameter _a of main\(_a: ?int\) is ' r'private but has no default'): defopt.run(main, argv=[])
def test_subcommands(self): def sub(*bar): """:type bar: float""" return bar def sub_with_dash(baz=None): """:type baz: int""" return baz self.assertEqual(defopt.run([sub, sub_with_dash], argv=['sub', '1.1']), (1.1, )) self.assertEqual( defopt.run([sub, sub_with_dash], strict_kwonly=False, argv=['sub-with-dash', '--baz', '1']), 1) self.assertEqual( defopt.run({ "sub1": sub, "sub_2": sub_with_dash }, strict_kwonly=False, argv=['sub1', '1.2']), (1.2, )) self.assertEqual( defopt.run({ "sub1": sub, "sub_2": sub_with_dash }, strict_kwonly=False, argv=['sub-2', '--baz', '1']), 1)
def test_incorrect_param_type() -> None: """A little test to demonstrate that when the input arg has the wrong type, a SystemExit is thrown with exit code 2""" with pytest.raises(SystemExit) as e: defopt.run(valid_docs_func, argv=["-a", "str"]) assert e.type == SystemExit assert e.value.code == 2 # code should be 2 for parse error
def test_var_positional(self): for doc in [ ":type foo: int", r":type \*foo: int", ":param int foo: doc"]: def main(*foo): return foo main.__doc__ = doc self.assertEqual(defopt.run(main, argv=['1', '2']), (1, 2)) self.assertEqual(defopt.run(main, argv=[]), ())
def test_no_version(self): for funcs in [[], lambda: None, [lambda: None]]: with self.assertRaises(SystemExit), \ self._assert_streams( stdout=r'\A\Z', stderr='unrecognized arguments: --version'): defopt.run([], version=False, argv=['--version'])
def test_optional(self): def main(foo=None): """:type foo: Choice""" return foo self.assertEqual(defopt.run(main, argv=['--foo', 'one']), Choice.one) self.assertIs(defopt.run(main, argv=[]), None)
def test_var_positional(self): def main(*foo): """:type foo: int""" return foo self.assertEqual(defopt.run(main, argv=['1', '2']), (1, 2)) self.assertEqual(defopt.run(main, argv=[]), ())
def test_list_keyword_only(self): def main(*, foo): """:type foo: list[int]""" return foo self.assertEqual(defopt.run(main, argv=['--foo', '1', '2']), [1, 2]) with self.assertRaises(SystemExit): defopt.run(main, argv=[])
def test_literal(self): def main(foo): """:param defopt.Literal["bar","baz"] foo: foo""" return foo self.assertEqual(defopt.run(main, argv=["bar"]), "bar") with self.assertRaises(SystemExit): defopt.run(main, argv=["quux"])
def test_no_default(self): def main(a): """:type a: str""" return a with self.assertRaises(SystemExit): defopt.run(main, argv=[])
def main(args: List[str] = None) -> None: """ Main entrypoint for the CLI. """ Logger.setup_root_logger() logger = Logger.get_logger("main") funcs = [ add_oxog_filters, create_dtoxog_maf, create_oxog_intervals, dtoxog_maf_to_vcf, extract_oxoq_from_sqlite, filter_contigs, filter_nonstandard_variants, filter_somatic_score, format_gdc_vcf, format_pindel_vcf, format_sanger_pindel_vcf, position_filter_dkfz, ] defopt.run( funcs, argv=args if args is not None else sys.argv[1:], version=True, argparse_kwargs={'prog': 'gdc_filtration_tools'}, ) logger.info("Finished!")
def test_keyword_only_no_default(self): def main(*, foo): """:type foo: str""" return foo self.assertEqual(defopt.run(main, argv=['--foo', 'baz']), 'baz') with self.assertRaises(SystemExit): defopt.run(main, argv=[])
def test_overridden_parser(self): def parser(string): return int(string) * 2 def main(value): """:type value: int""" self.assertEqual(value, 2) defopt.run(main, parsers={int: parser}, argv=['1'])
def test_bool_list_var_positional(self): def main(*foo): """:type foo: list[bool]""" return foo argv = ['--foo', '1', '--foo', '0', '0'] self.assertEqual(defopt.run(main, argv=argv), ([True], [False, False])) self.assertEqual(defopt.run(main, argv=[]), ())
def test_short_negation(self): def func(foo=False): """:type foo: bool""" return foo out = defopt.run(func, short={'foo': 'f', 'no-foo': 'F'}, argv=['-f']) self.assertIs(out, True) out = defopt.run(func, short={'foo': 'f', 'no-foo': 'F'}, argv=['-F']) self.assertIs(out, False)
def test_bool_var_positional(self): def main(*foo): """:type foo: bool""" return foo self.assertEqual(defopt.run(main, argv=['1', '1', '0']), (True, True, False)) self.assertEqual(defopt.run(main, argv=[]), ())
def test_list_kwarg(self): def main(foo=None): """Test function :type foo: list[float] """ self.assertEqual(foo, [1.1, 2.2]) defopt.run(main, argv=['--foo', '1.1', '2.2'])
def test_bool(self): def main(foo): """:type foo: bool""" return foo self.assertIs(defopt.run(main, argv=['1']), True) self.assertIs(defopt.run(main, argv=['0']), False) with self.assertRaises(SystemExit): defopt.run(main, argv=[])
def test_same(self): # Need to hide execution inside exec for Python 2's benefit. globals_ = {} exec(textwrap.dedent('''\ def foo(bar: int): """:type bar: int""" '''), globals_) defopt.run(globals_['foo'], argv='1')
def test_bool_keyword_only(self): def main(*, foo): """:type foo: bool""" return foo self.assertIs(defopt.run(main, argv=['--foo']), True) self.assertIs(defopt.run(main, argv=['--no-foo']), False) with self.assertRaises(SystemExit): defopt.run(main, argv=[])
def test_enum(self): def main(foo): """:type foo: Choice""" return foo self.assertEqual(defopt.run(main, argv=['one']), Choice.one) self.assertEqual(defopt.run(main, argv=['two']), Choice.two) with self.assertRaises(SystemExit): defopt.run(main, argv=['three'])
def run_main(): defopt.run([de_dimensions, featurecount_rename, merge_fc_deseq2, polya_length_correlation, scatter_plot, filter_bam_by_name, extract_sequences ])
def test_conflicting(self): # Need to hide execution inside exec for Python 2's benefit. globals_ = {} exec(textwrap.dedent('''\ def foo(bar: int): """:type bar: float""" '''), globals_) with self.assertRaisesRegex(ValueError, 'bar.*float.*int'): defopt.run(globals_['foo'], argv='1')
def main(): """wrapper function to create a CLI tool""" defopt.run( [fit, predict], parsers={ T.Union[pd.DataFrame, Path]: Path, T.Union[BaseEstimator, Path]: Path }, )
def test_registered_parser(self): @defopt.parser(int) def parser(string): return int(string) * 2 def main(value): """:type value: int""" self.assertEqual(value, 2) defopt.run(main, argv=['1'])
def test_bool_kwarg(self): default = object() def main(foo=default): """:type foo: bool""" return foo self.assertIs(defopt.run(main, argv=['--foo']), True) self.assertIs(defopt.run(main, argv=['--no-foo']), False) self.assertIs(defopt.run(main, argv=[]), default)
def main() -> None: '''The main entry point for all tools''' logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO) defopt.run([ add, add_all, ls, rm, rm_r, one_to_one, one_to_one_tuples, one_to_many, one_to_many_tuples ], parsers={KitStatus: KitStatus.from_name})
def test_no_subparser_specified(self): def sub1(): pass def sub2(): pass with self.assertRaises(SystemExit): defopt.run(sub1, sub2, argv=[])
def test_conflicting(self): globals_ = {} exec( textwrap.dedent('''\ def foo(bar: int): """:type bar: float""" '''), globals_) with self.assertRaisesRegex(ValueError, 'bar.*float.*int'): defopt.run(globals_['foo'], argv=['1'])
def test_same(self): # Need to hide execution inside exec for Python 2's benefit. globals_ = {} exec( textwrap.dedent('''\ def foo(bar: int): """:type bar: int""" '''), globals_) defopt.run(globals_['foo'], argv='1')
def test_return(self): def one(): return 1 def none(): pass self.assertEqual(defopt.run(one, none, argv=['one']), 1) self.assertEqual(defopt.run(one, none, argv=['none']), None)
def main(argv: List[str] = sys.argv[1:]) -> None: logger = logging.getLogger(__name__) if len(argv) != 0 and all(arg not in argv for arg in ["-h", "--help"]): logger.info("Running command: fgaws-tools " + " ".join(argv)) try: defopt.run(funcs=TOOLS, argv=argv, parsers=_parsers()) logger.info("Completed successfully.") except Exception as e: logger.info("Failed on command: " + " ".join(argv)) raise e
def test_conflicting(self): # Need to hide execution inside exec for Python 2's benefit. globals_ = {} exec( textwrap.dedent('''\ def foo(bar: int): """:type bar: float""" '''), globals_) with self.assertRaisesRegex(ValueError, 'bar.*float.*int'): defopt.run(globals_['foo'], argv='1')
def test_keyword_only(self): # Need to hide execution inside exec for Python 2's benefit. globals_ = {'self': self} exec(textwrap.dedent('''\ def main(*, foo='bar'): """:type foo: str""" self.assertEqual(foo, 'baz') self.calls += 1 '''), globals_) defopt.run(globals_['main'], argv=['--foo', 'baz']) self.assertEqual(self.calls, 1)
def test_subcommand(self): def sub1(foo): """:type foo: Choice""" self.assertEqual(foo, Choice.one) def sub2(bar): """:type bar: Choice""" self.assertEqual(bar, Choice.two) defopt.run(sub1, sub2, argv=['sub1', 'one']) defopt.run(sub1, sub2, argv=['sub2', 'two'])
def test_underscores(self): def main(a_b_c, d_e_f=None): """Test function :type a_b_c: int :type d_e_f: int """ return a_b_c, d_e_f self.assertEqual(defopt.run(main, argv=['1', '--d-e-f', '2']), (1, 2))
def test_enum(self): def main(foo): """:type foo: Choice""" defopt.run(main, argv=['one']) defopt.run(main, argv=['two']) with self.assertRaises(SystemExit): defopt.run(main, argv=['three'])
def numpy(integer, farewell=None): """Example function with a Numpy-style docstring. Squares a given integer. .. This is a comment; it won't show up anywhere but here. Below is a literal block which will be displayed with a 4-space indent in the help string and as a code block in the documentation. :: $ python styles.py numpy 2 --farewell goodbye! 4 goodbye! Parameters ---------- integer : int Number to square farewell : str Parting message """ print(integer ** 2) if farewell is not None: print(farewell) if __name__ == '__main__': defopt.run(sphinx, google, numpy)
def test_list(self): def main(foo): """:type foo: list[float]""" self.assertEqual(foo, [1.1, 2.2]) defopt.run(main, argv=['--foo', '1.1', '2.2'])
"""Example showing short flags in defopt. You can add alternative short flags to arguments by passing a dictionary to `defopt.run` which maps flag names to single letters. Code usage:: >>> main(count=2) Command line usage:: $ python short.py -c 2 $ python short.py --count 2 """ import defopt def main(count=1): """Example function which prints a message. :param int count: Number of times to print the message """ for _ in range(count): print('hello!') if __name__ == '__main__': defopt.run(main, short={'count': 'c'})
def test_subcommands(self): sub1, sub1_args = self._def_sub1() sub2, sub2_args = self._def_sub2() defopt.run(sub1, sub2, argv=sub1_args) defopt.run(sub1, sub2, argv=sub2_args) self.assertEqual(self.calls, 2)
def test_main(self): main, args = self._def_main() defopt.run(main, argv=args) self.assertEqual(self.calls, 1)
"""Example showing lists in defopt. Lists are automatically converted to required flags which accept zero or more arguments. Code usage:: >>> main([1.2, 3.4], 2) Command line usage:: $ python lists.py 2 --numbers 1.2 3.4 $ python lists.py --numbers 1.2 3.4 -- 2 """ import defopt def main(numbers, multiplier): """Example function with a list argument. :param list[float] numbers: Numbers to multiply :param float multiplier: Amount to multiply by """ print([x * multiplier for x in numbers]) if __name__ == '__main__': defopt.run(main)
def test_parser(self): def main(value): """:type value: int""" self.assertEqual(value, 1) defopt.run(main, argv=['1'])
def test_no_subparser_specified(self): sub1, _ = self._def_sub1() sub2, _ = self._def_sub2() with self.assertRaises(SystemExit): defopt.run(sub1, sub2, argv=[])
def test_none(self): def foo(bar): """No type information""" with self.assertRaisesRegex(ValueError, 'no type'): defopt.run(foo, argv='1')
def test_no_param_doc(self): def bad(foo): """Test function""" with self.assertRaisesRegex(ValueError, 'type.*foo'): defopt.run(bad, argv=['foo'])
def test_bad_arg(self): with self.assertRaises(TypeError): defopt.run(foo=None)
def test_no_function(self): with self.assertRaisesRegex(ValueError, 'at least one'): defopt.run()
def test_short_flags(self): def func(foo=1): """:type foo: int""" return foo out = defopt.run(func, short={'foo': 'f'}, argv=['-f', '2']) self.assertEqual(out, 2)
def test_optional(self): def main(foo=None): """:type foo: Choice""" defopt.run(main, argv=['--foo', 'one']) defopt.run(main, argv=[])
def test_var_keywords(self): def bad(**kwargs): """:type kwargs: str""" with self.assertRaises(ValueError): defopt.run(bad)
>>> documented([1.2, 3.4], 2) Command line usage:: $ python annotations.py documented 2 --numbers 1.2 3.4 $ python annotations.py documented --numbers 1.2 3.4 -- 2 """ from typing import Iterable import defopt def documented(numbers: Iterable[float], exponent: int) -> None: """Example function using annotations. I haven't yet found a good way of automatically filling in these types in the generated documentation. :param numbers: Numbers to multiply :param exponent: Power to raise each element to """ print([x ** exponent for x in numbers]) def undocumented(numbers: Iterable[float], exponent: int) -> None: print([x ** exponent for x in numbers]) if __name__ == '__main__': defopt.run(documented, undocumented)
def test_no_type_doc(self): def bad(foo): """:param foo: no type info""" with self.assertRaisesRegex(ValueError, 'type.*foo'): defopt.run(bad, argv=['foo'])