def test_sync_properties(self) -> None: """ Tests `sync_properties` with `call=False` """ with TemporaryDirectory() as tempdir: ( input_filename, input_str, output_filename, output_str, ) = populate_files(tempdir) self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("Foo.g.f", ), input_eval=False, output_filename=output_filename, output_params=("f.h", ), )) self.run_sync_properties_test( input_filename, input_str, output_filename, ast.parse( output_str.replace("h: Literal['b']", "f: Literal['a']")), )
def test_sync_properties_output_param_wrap_subscript(self) -> None: """ Tests `sync_properties` with `output_param_wrap` set when replacement_node is subscript and !input_eval """ with TemporaryDirectory() as tempdir: ( input_filename, input_str, output_filename, output_str, ) = populate_files( tempdir, input_str="a = tuple(range(5))", output_str="def j(k):\n" "{tab}pass\n".format(tab=tab), ) self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("a", ), input_eval=False, output_filename=output_filename, output_params=("j.k", ), output_param_wrap=None, )) with open(output_filename, "rt") as f: # Technically this produces an invalid AST, but we don't care… `input_eval is False` self.assertEqual( f.read().rstrip(), output_str.replace("(k)", "(a: tuple(range(5)))").rstrip(), )
def test_sync_properties_output_param_wrap_subscript_eval0(self) -> None: """ Tests `sync_properties` with `output_param_wrap` set when replacement_node is subscript """ with TemporaryDirectory() as tempdir: ( input_filename, input_str, output_filename, output_str, ) = populate_files(tempdir, input_str="a = tuple(range(5))", output_str="def j(k): pass") self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("a", ), input_eval=True, output_filename=output_filename, output_params=("j.k", ), output_param_wrap=None, )) self.run_sync_properties_test( input_filename=input_filename, output_filename=output_filename, input_str=input_str, gold=ast.parse( output_str.replace("(k)", "(k: Literal[0, 1, 2, 3, 4])")), )
def test_sync_properties_output_param_wrap(self) -> None: """ Tests `sync_properties` with `output_param_wrap` set """ with TemporaryDirectory() as tempdir: ( input_filename, input_str, output_filename, output_str, ) = populate_files(tempdir) self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("Foo.g.f", ), input_eval=False, output_filename=output_filename, output_params=("f.h", ), output_param_wrap= "Optional[List[Union[{output_param}, str]]]", )) self.run_sync_properties_test( input_filename=input_filename, output_filename=output_filename, input_str=input_str, gold=ast.parse( output_str.replace( "h: Literal['b']", "f: Optional[List[Union[Literal['a'], str]]]")), )
def test_sync_properties_output_param_wrap_no_type(self) -> None: """ Tests `sync_properties` with `output_param_wrap` set when replacement_node has no type """ with TemporaryDirectory() as tempdir: (input_filename, input_str, output_filename, output_str,) = populate_files( tempdir, output_str=( "from typing import Literal\n\n" "class Foo(object):\n" "{tab}def f(h):\n" "{tab}{tab}pass".format(tab=tab) ), ) self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("Foo.g.f",), input_eval=False, output_filename=output_filename, output_params=("Foo.f.h",), output_param_wrap="Optional[List[Union[{output_param}, str]]]", ) ) self.run_sync_properties_test( input_filename=input_filename, output_filename=output_filename, input_str=input_str, gold=ast.parse( output_str.replace( "(h)", "(f: Optional[List[Union[Literal['a'], str]]])" ) ), )
def test_sync_properties_output_param_wrap_no_annotation(self) -> None: """ Tests `sync_properties` with `output_param_wrap` set when type annotation isn't being replaced """ with TemporaryDirectory() as tempdir: (input_filename, input_str, output_filename, output_str,) = populate_files( tempdir, input_str=( "from typing import Literal\n\n" "class Foo(object):\n" "{tab}def g(f):\n" "{tab}{tab}pass".format(tab=tab) ), ) self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("Foo.g.f",), input_eval=False, output_filename=output_filename, output_params=("f.h",), output_param_wrap="Optional[List[Union[{output_param}, str]]]", ) ) self.run_sync_properties_test( input_filename=input_filename, output_filename=output_filename, input_str=input_str, gold=ast.parse(output_str.replace("h: Literal['b']", "f")), )
def test_sync_properties_eval(self) -> None: """ Tests `sync_properties` with `call=True` """ with open( os.path.join( os.path.dirname( os.path.dirname( resource_filename(modules[__name__].__name__, "__init__.py") ) ), "tests", "mocks", "eval.py", ), "rt", ) as f: eval_mock_str = f.read() with TemporaryDirectory() as tempdir: ( input_filename, input_str, output_filename, output_str, ) = populate_files(tempdir, input_str=eval_mock_str) self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("get_modules",), input_eval=True, output_filename=output_filename, output_params=("f.h",), ) ) self.run_sync_properties_test( input_filename=input_filename, output_filename=output_filename, input_str=eval_mock_str, gold=ast.parse( output_str.replace("h: Literal['b']", "h: Literal['mocks']") ), )
def test_sync_properties_eval_fails(self) -> None: """ Tests `sync_properties` fails with `call=True` and dots """ with TemporaryDirectory() as tempdir: input_filename = os.path.join(tempdir, "input_.py") output_filename = os.path.join(tempdir, "input_str.py") open(input_filename, "wt").close() open(output_filename, "wt").close() self.assertRaises( NotImplementedError, lambda: sync_properties( input_filename=input_filename, input_params=("foo.bar", ), input_eval=True, output_filename=output_filename, output_params=("f.h", ), ), )
def test_sync_properties_output_param_wrap_subscript_eval1(self) -> None: """ Tests `sync_properties` with `output_param_wrap` set when replacement_node is subscript """ with TemporaryDirectory() as tempdir: ( input_filename, input_str, output_filename, output_str, ) = populate_files( tempdir, input_str="import pip\n" "c = { attr: getattr(pip, attr)" " for attr in dir(pip)" " if attr in frozenset(('__version__', '__name__')) }\n" "a = tuple(sorted(c.keys()))\n", output_str="class C(object):\n" "{tab}def j(k: str):\n" "{tab}{tab}pass\n".format(tab=tab), ) self.assertIsNone( sync_properties( input_filename=input_filename, input_params=("a", ), input_eval=True, output_filename=output_filename, output_params=("C.j.k", ), output_param_wrap=None, )) self.run_sync_properties_test( input_filename=input_filename, output_filename=output_filename, input_str=input_str, gold=ast.parse( output_str.replace( "(k: str)", "(k: Literal['__name__', '__version__'])")), )
def test_sync_properties_output_param_wrap_fails(self) -> None: """ Tests `sync_properties` fails with `output_param_wrap` set when replacement_node is unknown """ with TemporaryDirectory() as tempdir: ( input_filename, input_str, output_filename, output_str, ) = populate_files(tempdir, input_str="local = locals()") self.assertRaises( NotImplementedError, lambda: sync_properties( input_filename=input_filename, input_params=("local",), input_eval=False, output_filename=output_filename, output_params=("f.h",), output_param_wrap="Optional[List[Union[{output_param}, str]]]", ), )
def main(cli_argv=None, return_args=False): """ Run the CLI parser :param cli_argv: CLI arguments. If None uses `sys.argv`. :type cli_argv: ```Optional[List[str]]``` :param return_args: Primarily use is for tests. Returns the args rather than executing anything. :type return_args: ```bool``` :returns: the args if `return_args`, else None :rtype: ```Optional[Namespace]``` """ _parser = _build_parser() args = _parser.parse_args(args=cli_argv) command = args.command args_dict = {k: v for k, v in vars(args).items() if k != "command"} if command == "sync": args = Namespace( **{ k: v if k == "truth" or isinstance(v, list) or v is None else [v] for k, v in args_dict.items() }) truth_file = getattr(args, pluralise(args.truth)) if truth_file is None: _parser.error("--truth must be an existent file. Got: None") else: truth_file = truth_file[0] truth_file = path.realpath(path.expanduser(truth_file)) number_of_files = sum( len(val) for key, val in vars(args).items() if isinstance(val, list) and not key.endswith("_names")) if number_of_files < 2: _parser.error( "Two or more of `--argparse-function`, `--class`, and `--function` must" " be specified") elif truth_file is None or not path.isfile(truth_file): _parser.error("--truth must be an existent file. Got: {!r}".format( truth_file)) return args if return_args else ground_truth(args, truth_file) elif command == "sync_properties": for fname in "input_filename", "output_filename": if path.isfile(getattr(args, fname)): setattr(args, fname, path.realpath(path.expanduser(getattr(args, fname)))) if args.input_filename is None or not path.isfile(args.input_filename): _parser.error( "--input-file must be an existent file. Got: {!r}".format( args.input_filename)) elif args.output_filename is None or not path.isfile( args.output_filename): _parser.error( "--output-file must be an existent file. Got: {!r}".format( args.output_filename)) sync_properties(**args_dict) elif command == "gen": if path.isfile(args.output_filename): raise IOError( "File exists and this is a destructive operation. Delete/move {!r} then" " rerun.".format(args.output_filename)) gen(**args_dict)