def test_to_function(self) -> None: """ Tests whether `function` produces method from `class_with_method_types_ast` given `docstring_str` """ function_def = reindent_docstring( 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( parse.docstring(docstring_str), function_name=function_name, function_type=function_type, emit_default_doc=False, type_annotations=True, emit_separating_tab=True, indent_level=1, emit_as_kwonlyargs=False, ) run_ast_test( self, gen_ast=gen_ast, gold=function_def, )
def test_to_function_emit_as_kwonlyargs(self) -> None: """ Tests whether `function` produces method with keyword only arguments """ function_def = reindent_docstring( deepcopy( next( filter( rpartial(isinstance, FunctionDef), ast.parse( class_with_method_types_str.replace( "self", "self, *")).body[0].body, )))) 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, type_annotations=True, emit_separating_tab=True, indent_level=1, emit_as_kwonlyargs=True, ) run_ast_test( self, gen_ast=gen_ast, gold=function_def, )
def test_to_function_with_type_annotations(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) reindent_docstring(function_def) gen_ast = emit.function( parse.function( function_def, function_name=function_name, function_type=function_type, ), function_name=function_name, function_type=function_type, emit_default_doc=False, type_annotations=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_ast_expr_with_list(self) -> None: """ Tests that param2argparse_param works to change the type based on the default whence said default is an ast.List inside an ast.Expr """ run_ast_test( gen_ast=param2argparse_param( ( "byo", { "default": Expr( List( elts=[], ctx=Load(), expr=None, ), expr_value=None, ), "typ": "str", }, ), ), gold=argparse_add_argument_expr, test_case_instance=self, )
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_param2argparse_param_default_simple_type(self) -> None: """ Tests that param2argparse_param works to change the type based on the default """ run_ast_test( gen_ast=param2argparse_param( ("byo", {"default": 5, "typ": "str"}), ), gold=Expr( Call( args=[set_value("--byo")], func=Attribute( Name("argument_parser", Load()), "add_argument", Load(), ), keywords=[ keyword(arg="type", value=Name("int", Load()), identifier=None), keyword(arg="required", value=set_value(True), identifier=None), keyword(arg="default", value=set_value(5), identifier=None), ], expr=None, expr_func=None, ) ), test_case_instance=self, )
def test_gen(self) -> None: """Tests `gen`""" output_filename = os.path.join( self.tempdir, "test_gen_output{extsep}py".format(extsep=extsep)) 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", emit_name="class", parse_name="infer", 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_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_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 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_to_function_with_docstring_types(self) -> None: """ Tests that `function` can generate a function_def with types in docstring """ # Sanity check run_ast_test( self, class_with_method_ast, gold=ast.parse(class_with_method_str).body[0], ) function_def = reindent_docstring( deepcopy( next( filter(rpartial(isinstance, FunctionDef), class_with_method_ast.body)))) ir = parse.function(function_def) gen_ast = reindent_docstring( emit.function( ir, function_name=function_def.name, function_type=get_function_type(function_def), emit_default_doc=False, type_annotations=False, indent_level=1, emit_separating_tab=True, emit_as_kwonlyargs=False, word_wrap=False, )) run_ast_test(self, gen_ast=gen_ast, gold=function_def)
def test_from_class_with_body_in_method_to_method_with_body(self) -> None: """Tests if this can make the roundtrip from a full function to a full function""" annotate_ancestry(class_with_method_and_body_types_ast) function_def = reindent_docstring( next( filter( rpartial(isinstance, FunctionDef), class_with_method_and_body_types_ast.body, ))) ir = parse.function( find_in_ast( "C.function_name".split("."), class_with_method_and_body_types_ast, ), ) gen_ast = emit.function( ir, emit_default_doc=False, function_name="function_name", function_type="self", indent_level=1, emit_separating_tab=True, emit_as_kwonlyargs=False, ) # emit.file(gen_ast, os.path.join(os.path.dirname(__file__), # "delme{extsep}py".format(extsep=extsep), mode="wt") run_ast_test( self, gen_ast=gen_ast, gold=function_def, )
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_to_sqlalchemy_table(self): """ Tests that `emit.sqlalchemy_table` with `intermediate_repr_no_default_sql_doc` produces `config_tbl_ast` """ run_ast_test( self, emit.sqlalchemy_table( deepcopy(intermediate_repr_no_default_sql_doc), name="config_tbl"), gold=config_tbl_ast, )
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, word_wrap=True) run_ast_test( self, *map(reindent_docstring, (func, argparse_func_with_body_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_doctrans_function_from_docstring_to_annotated(self) -> None: """Tests `DocTrans` converts docstring function to type annotated function""" original_node = annotate_ancestry(deepcopy(function_type_in_docstring)) doc_trans = DocTrans( docstring_format="rest", type_annotations=True, existing_type_annotations=False, whole_ast=original_node, ) gen_ast = doc_trans.visit(original_node) run_ast_test(self, gen_ast, gold=function_type_annotated)
def test_class_with_internal_converts_to_annotated(self) -> None: """Tests that class, function, and class variable hierarchy is correctly converts to annotated""" original_node = annotate_ancestry( deepcopy(class_with_internal_type_commented_and_docstring_typed)) doc_trans = DocTrans( docstring_format="rest", type_annotations=True, existing_type_annotations=False, whole_ast=original_node, ) gen_ast = doc_trans.visit(original_node) run_ast_test(self, gen_ast=gen_ast, gold=class_with_internal_annotated)
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=argparse_add_argument_expr, 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, function_name="set_cli_action_append", ), gold=argparse_func_action_append_ast, )
def test_doctrans_assign_to_assign(self) -> None: """ Tests that `AnnAssign` converts to `Assign` """ original_node = annotate_ancestry(deepcopy(assign_with_type_comment)) doc_trans = DocTrans( docstring_format="rest", type_annotations=False, existing_type_annotations=False, whole_ast=original_node, ) gen_ast = doc_trans.visit(original_node) run_ast_test(self, gen_ast=gen_ast, gold=assign_with_type_comment)
def test_to_argparse(self) -> None: """ Tests whether `to_argparse` produces `argparse_func_ast` given `class_ast` """ run_ast_test( self, reindent_docstring( emit.argparse_function( parse.class_(class_ast), emit_default_doc=False, )), gold=reindent_docstring(argparse_func_ast), )
def test_module_docstring(self) -> None: """Tests that module gets the right new docstring""" module_node = Module(body=[Expr(set_value("\nModule\n"))], stmt=None, type_ignores=[]) original = deepcopy(module_node) doc_trans = DocTrans( docstring_format="rest", type_annotations=True, existing_type_annotations=True, whole_ast=module_node, ) doc_trans.visit_Module(module_node) run_ast_test(self, gen_ast=module_node, gold=original)
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{extsep}py" .format(extsep=extsep), ) 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", emit_name="class", parse_name="infer", 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_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_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, wrap_description=False, word_wrap=False, ) run_ast_test( self, func, argparse_func_torch_nn_l1loss_ast, )
def test__get_ass_typ(self) -> None: """Tests that _get_ass_typ returns when location isn't set""" original_node = annotate_ancestry(deepcopy(assign_with_type_comment)) doc_trans = DocTrans( docstring_format="rest", type_annotations=True, existing_type_annotations=True, whole_ast=original_node, ) del original_node._location run_ast_test( self, gen_ast=doc_trans._get_ass_typ(original_node), gold=Name("int", Load()), )