def test_to_named_class_def(self) -> None: """ Test that find_ast_type gives the wrapped named class back """ class_def = ClassDef( name="foo", bases=tuple(), keywords=tuple(), decorator_list=[], body=[], expr=None, identifier_name=None, ) run_ast_test( self, find_ast_type( Module( body=[ ClassDef( name="bar", bases=tuple(), keywords=tuple(), decorator_list=[], body=[], expr=None, identifier_name=None, ), class_def, ], stmt=None, ), node_name="foo", ), class_def, skip_black=True, )
def test_gen(self) -> None: """ Tests `gen` """ output_filename = os.path.join(self.tempdir, "test_gen_output.py") with patch("sys.stdout", new_callable=StringIO), patch( "sys.stderr", new_callable=StringIO ): self.assertIsNone( gen( name_tpl="{name}Config", input_mapping="gen_test_module.input_map", type_="class", output_filename=output_filename, prepend="PREPENDED\n", emit_call=True, emit_default_doc=False, ) ) with open(output_filename, "rt") as f: gen_module_str = f.read() gen_module_ast = ast.parse(gen_module_str) run_ast_test( self, gen_ast=next(filter(rpartial(isinstance, ClassDef), gen_module_ast.body)), gold=self.expected_class_ast, )
def test_replace_in_ast_with_val_on_non_function(self) -> None: """ Tests that `RewriteAtQuery` can actually replace a node at given location """ parsed_ast = ast_parse(class_str) rewrite_at_query = RewriteAtQuery( search="ConfigClass.dataset_name".split("."), replacement_node=AnnAssign( annotation=Name("int", Load()), simple=1, target=Name("dataset_name", Store()), value=set_value(15), expr=None, expr_target=None, expr_annotation=None, ), ) gen_ast = rewrite_at_query.visit(parsed_ast) self.assertTrue(rewrite_at_query.replaced, True) run_ast_test( self, gen_ast, ast.parse( class_str.replace('dataset_name: str = "mnist"', "dataset_name: int = 15")), )
def run_sync_properties_test(self, input_filename, input_str, output_filename, gold): """ Common test for the suite :param input_filename: Filename of input :type input_filename: ```str``` :param input_str: Python source :type input_str: ```str``` :param output_filename: Filename of output :type output_filename: ```str``` :param gold: Gold standard AST :type gold: ```Union[ast.Module, ast.ClassDef, ast.FunctionDef]``` """ # Confirm that the input_filename is unedited with open(input_filename, "rt") as f: run_ast_test(self, gen_ast=ast.parse(input_str), gold=ast.parse(f.read())) # Confirm that the output_filename is edited correctly with open(output_filename, "rt") as f: run_ast_test( self, gen_ast=ast.parse(f.read()), gold=gold, )
def test_emit_ann_assign(self) -> None: """ Tests that AnnAssign is emitted from `emit_ann_assign` """ self.assertIsInstance(class_ast.body[1], AnnAssign) self.assertIsInstance(emit_ann_assign(class_ast.body[1]), AnnAssign) self.assertIsInstance(emit_ann_assign(class_ast.body[1]), AnnAssign) gen_ast = emit_ann_assign( find_in_ast( "C.function_name.dataset_name".split("."), class_with_method_and_body_types_ast, )) self.assertIsInstance(gen_ast, AnnAssign) run_ast_test( self, gen_ast, AnnAssign( annotation=Name( "str", Load(), ), simple=1, target=Name("dataset_name", Store()), value=set_value("~/tensorflow_datasets"), expr=None, expr_target=None, expr_annotation=None, ), )
def test_param2argparse_param_none_default(self) -> None: """ Tests that param2argparse_param works to reparse the default """ run_ast_test( gen_ast=param2argparse_param(("yup", { "default": NoneStr })), gold=Expr( Call( args=[set_value("--yup")], func=Attribute( Name("argument_parser", Load()), "add_argument", Load(), ), keywords=[ keyword(arg="type", value=Name("str", Load()), identifier=None), keyword(arg="default", value=set_value(None), identifier=None), ], expr=None, expr_func=None, )), test_case_instance=self, )
def test_to_function_with_inline_types(self) -> None: """ Tests that `function` can generate a function_def with inline types """ function_def = deepcopy( next( filter( rpartial(isinstance, FunctionDef), class_with_method_types_ast.body ) ) ) function_name = function_def.name function_type = get_function_type(function_def) gen_ast = emit.function( intermediate_repr=parse.function( function_def=function_def, function_name=function_name, function_type=function_type, ), function_name=function_name, function_type=function_type, emit_default_doc=False, inline_types=True, emit_separating_tab=True, indent_level=1, emit_as_kwonlyargs=False, ) # emit.file(gen_ast, os.path.join(os.path.dirname(__file__), 'delme.py'), mode='wt') run_ast_test( self, gen_ast=gen_ast, gold=function_def, )
def test_param2argparse_param_default_list(self) -> None: """ Tests that param2argparse_param works to change the type based on the default whence said default is a list """ run_ast_test( gen_ast=param2argparse_param(("byo", { "default": [], "typ": "str" }), ), gold=Expr( Call( args=[set_value("--byo")], func=Attribute( Name("argument_parser", Load()), "add_argument", Load(), ), keywords=[ keyword(arg="action", value=set_value("append"), identifier=None), keyword(arg="required", value=set_value(True), identifier=None), ], expr=None, expr_func=None, ), ), test_case_instance=self, )
def test_argparse_func(self) -> None: """ Tests whether the `argparse_func_str` correctly produces `argparse_func_ast` """ run_ast_test( self, *map( reindent_docstring, (ast.parse(argparse_func_str).body[0], argparse_func_ast), ))
def test_to_class_from_argparse_action_append_ast(self) -> None: """ Tests whether a class from an argparse function with `nargs` set """ run_ast_test( self, emit.class_( parse.argparse_ast(argparse_func_action_append_ast), ), gold=class_nargs_ast, )
def test_to_class_from_argparse_ast(self) -> None: """ Tests whether `class_` produces `class_ast` given `argparse_func_ast` """ run_ast_test( self, gen_ast=emit.class_( parse.argparse_ast(argparse_func_ast), emit_default_doc=True ), gold=class_ast, )
def test_param2argparse_param_default_function(self) -> None: """ Tests that param2argparse_param works to change the type based on the default whence said default is an in-memory function """ function_str = ( "from operator import add\n" "def adder(a, b):\n" "{tab}return add(a, b)".format(tab=tab) ) adder = getattr( inspectable_compile(function_str), "adder", ) pickled_adder = pickle.dumps(adder) # eww run_ast_test( gen_ast=param2argparse_param( ( "byo", { "default": adder, "typ": "str", }, ), ), gold=Expr( Call( args=[set_value("--byo")], func=Attribute( Name("argument_parser", Load()), "add_argument", Load(), ), keywords=[ keyword( arg="type", value=Name("pickle.loads", Load()), identifier=None, ), keyword( arg="default", value=set_value(pickled_adder), identifier=None, ), ], expr=None, expr_func=None, ) ), test_case_instance=self, )
def test_to_class_from_docstring_str(self) -> None: """ Tests whether `class_` produces `class_ast` given `docstring_str` """ run_ast_test( self, emit.class_( parse.docstring(docstring_str, emit_default_doc=True), emit_default_doc=True, ), gold=class_ast, )
def test_from_torch_ir_to_argparse(self) -> None: """ Tests if emission of class from torch IR is as expected """ func = emit.argparse_function( deepcopy(class_torch_nn_l1loss_ir), emit_default_doc=False, emit_default_doc_in_return=False, ) run_ast_test( self, func, argparse_func_torch_nn_l1loss_ast, )
def test_to_argparse(self) -> None: """ Tests whether `to_argparse` produces `argparse_func_ast` given `class_ast` """ run_ast_test( self, emit.argparse_function( parse.class_(class_ast), emit_default_doc=False, emit_default_doc_in_return=False, ), gold=argparse_func_ast, )
def test_gen_with_imports_from_file_and_prepended_import(self) -> None: """ Tests `gen` with `imports_from_file` and `prepend` """ output_filename = os.path.join( self.tempdir, "test_gen_with_imports_from_file_and_prepended_import_output.py", ) with patch("sys.stdout", new_callable=StringIO), patch( "sys.stderr", new_callable=StringIO ): self.assertIsNone( gen( name_tpl="{name}Config", input_mapping="gen_test_module.input_map", imports_from_file="gen_test_module", type_="class", prepend=_import_gen_test_module_str, output_filename=output_filename, emit_call=True, emit_default_doc=False, ) ) with open(output_filename, "rt") as f: gen_ast = ast.parse(f.read()) gold = Module( body=[ _import_gen_test_module_ast, _import_star_from_input_ast, self.expected_class_ast, # self.input_module_ast.body[1], Assign( targets=[Name("__all__", Store())], value=List( ctx=Load(), elts=[set_value("FooConfig")], expr=None, ), expr=None, lineno=None, **maybe_type_comment ), ], type_ignores=[], stmt=None, ) run_ast_test( self, gen_ast=gen_ast, gold=gold, )
def test_from_argparse_with_extra_body_to_argparse_with_extra_body(self) -> None: """ Tests if this can make the roundtrip from a full argparse function to a argparse full function """ ir = parse.argparse_ast(argparse_func_with_body_ast) func = emit.argparse_function( ir, emit_default_doc=False, emit_default_doc_in_return=False, ) run_ast_test( self, func, argparse_func_with_body_ast, )
def test_param2argparse_param_default_torch(self) -> None: """ Tests that param2argparse_param works to change the type based on the default whence said default is a proxy for an internal PyTorch type """ class FakeTorch(object): """ Not a real torch """ def __str__(self): """But a real str :returns: An actual str :rtype: ```Literal['<required parameter>']``` """ return "<required parameter>" # type("FakeTorch", tuple(), {"__str__": lambda _: "<required parameter>"}) run_ast_test( gen_ast=param2argparse_param( ( "byo", { "default": FakeTorch(), }, ), ), gold=Expr( Call( args=[set_value("--byo")], func=Attribute( Name("argument_parser", Load()), "add_argument", Load(), ), keywords=[ keyword( arg="type", value=Name(FakeTorch.__name__, Load()), identifier=None, ), keyword(arg="required", value=set_value(True), identifier=None), ], expr=None, expr_func=None, ) ), test_case_instance=self, )
def test_to_argparse_func_nargs(self) -> None: """ Tests whether an argparse function is generated with `action="append"` set properly """ run_ast_test( self, gen_ast=emit.argparse_function( parse.class_(class_nargs_ast), emit_default_doc=False, emit_default_doc_in_return=False, function_name="set_cli_action_append", ), gold=argparse_func_action_append_ast, )
def test_to_argparse_google_tf_tensorboard(self) -> None: """ Tests whether `to_argparse` produces `argparse_function_google_tf_tensorboard_ast` given `class_google_tf_tensorboard_ast` """ run_ast_test( self, emit.argparse_function( parse.class_( class_google_tf_tensorboard_ast, merge_inner_function="__init__" ), emit_default_doc=False, emit_default_doc_in_return=False, ), gold=argparse_function_google_tf_tensorboard_ast, )
def test_from_sqlalchemy(self) -> None: """ Tests that `parse.sqlalchemy` produces `intermediate_repr_no_default_sql_doc` properly """ # Sanity check run_ast_test( self, config_decl_base_ast, gold=ast.parse(config_decl_base_str).body[0], ) ir = parse.sqlalchemy(config_decl_base_ast) self.assertEqual(ir["name"], "config_tbl") ir["name"] = None self.assertDictEqual(ir, intermediate_repr_no_default_sql_doc)
def test_to_function_emit_as_kwonlyargs(self) -> None: """ Tests whether `function` produces method with keyword only arguments """ function_def = deepcopy( next( filter( rpartial(isinstance, FunctionDef), ast.parse(class_with_method_types_str.replace("self", "self, *")) .body[0] .body, ) ) ) # Reindent docstring function_def.body[0].value.value = "\n{tab}{docstring}\n{tab}".format( tab=tab, docstring=reindent( deindent(ast.get_docstring(function_def)), ), ) function_name = function_def.name function_type = get_function_type(function_def) gen_ast = emit.function( parse.docstring(docstring_str), function_name=function_name, function_type=function_type, emit_default_doc=False, inline_types=True, emit_separating_tab=PY3_8, indent_level=0, emit_as_kwonlyargs=True, ) gen_ast.body[0].value.value = "\n{tab}{docstring}".format( tab=tab, docstring=reindent(deindent(ast.get_docstring(gen_ast))) ) run_ast_test( self, gen_ast=gen_ast, gold=function_def, )
def test_find_in_ast_no_val(self) -> None: """Tests that `find_in_ast` correctly gives AST node from `def class C(object): def function_name(self,dataset_name: str,…)`""" run_ast_test( self, find_in_ast( "C.function_name.dataset_name".split("."), class_with_optional_arg_method_ast, ), set_arg( annotation=Name( "str", Load(), ), arg="dataset_name", ), )
def test_param2ast_with_assign_dict(self) -> None: """ Check that `param2ast` behaves correctly with dict type """ run_ast_test( self, param2ast(("menthol", { "typ": "dict" }), ), gold=AnnAssign( annotation=set_slice(Name("dict", Load())), simple=1, target=Name("menthol", Store()), value=Dict(keys=[], values=[], expr=None), expr=None, expr_target=None, expr_annotation=None, ), )
def test_param2ast_with_assign(self) -> None: """ Check that `param2ast` behaves correctly with a non annotated (typeless) input """ run_ast_test( self, param2ast(("zion", { "typ": None }), ), gold=AnnAssign( annotation=Name("object", Load()), simple=1, target=Name("zion", Store()), value=set_value(None), expr=None, expr_target=None, expr_annotation=None, ), )
def test_find_ast_type(self) -> None: """ Test that `find_ast_type` gives the wrapped class back """ class_def = ClassDef( name="", bases=tuple(), keywords=tuple(), decorator_list=[], body=[], expr=None, identifier_name=None, ) run_ast_test( self, find_ast_type(Module(body=[class_def], stmt=None)), class_def, skip_black=True, )
def test_param2ast_with_wrapped_default(self) -> None: """ Check that `param2ast` behaves correctly with a wrapped default """ run_ast_test( self, param2ast( ("zion", {"typ": None, "default": set_value(NoneStr)}), ), gold=AnnAssign( annotation=Name("object", Load()), simple=1, target=Name("zion", Store()), value=set_value(None), expr=None, expr_target=None, expr_annotation=None, ), )
def test_from_function_google_tf_squared_hinge_str_to_class(self) -> None: """ Tests that `emit.function` produces correctly with: - __call__ """ gen_ast = emit.class_( parse.function( ast.parse(function_google_tf_squared_hinge_str).body[0], infer_type=True, ), class_name="SquaredHingeConfig", emit_call=True, emit_default_doc=True, ) run_ast_test( self, gen_ast=gen_ast, gold=class_squared_hinge_config_ast, )
def test_emit_arg(self) -> None: """ Tests that `arg` is emitted from `emit_arg` """ self.assertIsInstance( class_with_method_and_body_types_ast.body[1].args.args[1], arg) self.assertIsInstance( emit_arg( class_with_method_and_body_types_ast.body[1].args.args[1]), arg) assign = Assign(targets=[Name("yup", Store())], value=set_value("nup"), expr=None, **maybe_type_comment) gen_ast = emit_arg(assign) self.assertIsInstance(gen_ast, arg) run_ast_test( self, gen_ast=gen_ast, gold=set_arg("yup"), )
def test_find_in_ast(self) -> None: """ Tests that `find_in_ast` successfully finds nodes in AST """ run_ast_test( self, find_in_ast("ConfigClass.dataset_name".split("."), class_ast), AnnAssign( annotation=Name( "str", Load(), ), simple=1, target=Name("dataset_name", Store()), value=set_value("mnist"), expr=None, expr_target=None, expr_annotation=None, ), )