def test_multiple_add_assignment(self): # To make our code generation easier to reason about, we disallow # assigning to same name twice. We can add trimming of unneeded # temporaries as a later pass. module = codegen.Module() name = module.scope.reserve_name('x') module.add_assignment(name, codegen.String('a string')) self.assertRaises(AssertionError, module.add_assignment, name, codegen.String('another string'))
def test_string_join_collapse_strings(self): scope = codegen.Scope() scope.reserve_name('tmp', properties={codegen.PROPERTY_TYPE: text_type}) var = scope.variable('tmp') join1 = codegen.ConcatJoin.build([ codegen.String('hello '), codegen.String('there '), var, codegen.String(' how'), codegen.String(' are you?'), ]) self.assertCodeEqual(as_source_code(join1), "'hello there ' + tmp + ' how are you?'")
def test_try_catch_has_assignment_for_name_2(self): scope = codegen.Scope() try_ = codegen.Try([], scope) name = scope.reserve_name('foo') # Add to 'except' try_.except_block.add_assignment(name, codegen.String('x')) self.assertFalse(try_.has_assignment_for_name(name)) # Add to 'else' try_.else_block.add_assignment(name, codegen.String('x'), allow_multiple=True) self.assertTrue(try_.has_assignment_for_name(name))
def test_try_catch_has_assignment_for_name_1(self): scope = codegen.Scope() try_ = codegen.Try([], scope) name = scope.reserve_name('foo') self.assertFalse(try_.has_assignment_for_name(name)) # Just add to 'try' block try_.try_block.add_assignment(name, codegen.String('x')) # Not all branches define name, so overall can't trust the name # to be defined at the end. self.assertFalse(try_.has_assignment_for_name(name)) # Now add to 'except' block as well try_.except_block.add_assignment(name, codegen.String('x'), allow_multiple=True) self.assertTrue(try_.has_assignment_for_name(name))
def test_function_call_bad_kwarg_names(self): module = codegen.Module() module.scope.reserve_name('a_function') allowed_args = [ # (name, allowed) pairs. # We allow reserved names etc. because we can # call these using **{} syntax ('hyphen-ated', True), ('class', True), ('True', True), (' pre_space', False), ('post_space ', False), ('mid space', False), ('valid_arg', True), ] for arg_name, allowed in allowed_args: func_call = codegen.FunctionCall('a_function', [], {arg_name: codegen.String("a")}, module.scope) if allowed: output = as_source_code(func_call) self.assertNotEqual(output, '') if not allowable_name(arg_name): self.assertIn('**{', output) else: self.assertRaises(AssertionError, as_source_code, func_call)
def test_add_assignment_reserved(self): module = codegen.Module() name = module.scope.reserve_name('x') module.add_assignment(name, codegen.String('a string')) self.assertCodeEqual(as_source_code(module), """ x = 'a string' """)
def test_add_assignment_bad(self): module = codegen.Module() name = module.scope.reserve_name('x') module.add_assignment(name, codegen.String('a string')) # We have to modify internals to force the error path, because # add_assignment already does checking module.statements[0].name = 'something with a space' self.assertRaises(AssertionError, as_source_code, module)
def test_function_return(self): module = codegen.Module() func = codegen.Function('myfunc', parent_scope=module) func.add_return(codegen.String("Hello")) self.assertCodeEqual(as_source_code(func), """ def myfunc(): return 'Hello' """)
def test_try_catch(self): scope = codegen.Scope() scope.reserve_name('MyError') try_ = codegen.Try([scope.variable('MyError')], scope) self.assertCodeEqual(as_source_code(try_), """ try: pass except MyError: pass """) scope.reserve_name('x') scope.reserve_name('y') scope.reserve_name('z') try_.try_block.add_assignment('x', codegen.String("x")) try_.except_block.add_assignment('y', codegen.String("y")) try_.else_block.add_assignment('z', codegen.String("z")) self.assertCodeEqual(as_source_code(try_), """ try: x = 'x' except MyError: y = 'y' else: z = 'z' """)
def test_or(self): or_ = codegen.Or(codegen.String('x'), codegen.String('y')) self.assertCodeEqual(as_source_code(or_), "'x' or 'y'")
def test_equals(self): eq = codegen.Equals(codegen.String('x'), codegen.String('y')) self.assertCodeEqual(as_source_code(eq), "'x' == 'y'")
def test_dict_lookup(self): scope = codegen.Scope() scope.reserve_name('tmp') var = scope.variable('tmp') lookup = codegen.DictLookup(var, codegen.String('x')) self.assertCodeEqual(as_source_code(lookup), "tmp['x']")
def test_function_call_args_and_kwargs(self): module = codegen.Module() module.scope.reserve_name('a_function') func_call = codegen.FunctionCall('a_function', [codegen.Number(123)], {'x': codegen.String("hello")}, module.scope) self.assertCodeEqual(as_source_code(func_call), "a_function(123, x='hello')")
def test_f_string_join_two(self): module = codegen.Module() module.scope.reserve_name('tmp', properties={codegen.PROPERTY_TYPE: text_type}) var = module.scope.variable('tmp') join = codegen.FStringJoin([codegen.String('hello '), var]) self.assertCodeEqual(as_source_code(join), "f'hello {tmp}'")
def test_string_join_one(self): join = codegen.StringJoin.build([codegen.String('hello')]) self.assertCodeEqual(as_source_code(join), "'hello'")
def test_string(self, t): self.assertEqual(t, eval(as_source_code(codegen.String(t))), " for t = {!r}".format(t))
def test_method_call_bad_name(self): scope = codegen.Module() s = codegen.String("x") method_call = codegen.MethodCall(s, 'bad method name', [], scope) self.assertRaises(AssertionError, as_source_code, method_call)
def test_add_assignment_unreserved(self): scope = codegen.Module() self.assertRaises(AssertionError, scope.add_assignment, 'x', codegen.String('a string'))