"""Tests xonsh contexts.""" from textwrap import dedent from tools import check_exec from xonsh.contexts import Block, Functor import pytest @pytest.fixture(autouse=True) def xonsh_execer_autouse(xonsh_builtins, xonsh_execer): return xonsh_execer # # helpers # X1_WITH = ('x = 1\n' 'with! Block() as b:\n') SIMPLE_WITH = 'with! Block() as b:\n' FUNC_WITH = ('x = 1\n' 'def func():\n' ' y = 1\n' ' with! Block() as b:\n' '{body}' ' y += 1\n' ' return b\n' 'x += 1\n' 'rtn = func()\n' 'x += 1\n') FUNC_OBSG = {'x': 3} FUNC_OBSL = {'y': 1} def norm_body(body): if not isinstance(body, str): body = '\n'.join(body) body = dedent(body) body = body.splitlines() return body def block_checks_glb(name, glbs, body, obs=None): block = glbs[name] obs = obs or {} for k, v in obs.items(): assert v == glbs[k] body = norm_body(body) assert body == block.lines assert glbs is block.glbs assert block.locs is None def block_checks_func(name, glbs, body, obsg=None, obsl=None): block = glbs[name] obsg = obsg or {} for k, v in obsg.items(): assert v == glbs[k] body = norm_body(body) assert body == block.lines assert glbs is block.glbs # local context tests locs = block.locs assert locs is not None obsl = obsl or {} for k, v in obsl.items(): assert v == locs[k] # # Block tests # def test_block_noexec(): s = ('x = 1\n' 'with! Block():\n' ' x += 42\n') glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) assert 1 == glbs['x'] def test_block_oneline(): body = ' x += 42\n' s = X1_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, body, {'x': 1}) def test_block_manylines(): body = (' ![echo wow mom]\n' '# bad place for a comment\n' ' x += 42') s = X1_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, body, {'x': 1}) def test_block_leading_comment(): # leading comments do not show up in block lines body = (' # I am a leading comment\n' ' x += 42\n') s = X1_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, [' x += 42'], {'x': 1}) def test_block_trailing_comment(): # trailing comments show up in block lines body = (' x += 42\n' ' # I am a trailing comment\n') s = X1_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, body, {'x': 1}) def test_block_trailing_line_continuation(): body = (' x += \\\n' ' 42\n') s = X1_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, body, {'x': 1}) def test_block_trailing_close_paren(): body = (' x += int("42"\n' ' )\n') s = X1_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, body, {'x': 1}) def test_block_trailing_close_many(): body = (' x = {None: [int("42"\n' ' )\n' ' ]\n' ' }\n') s = SIMPLE_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, body) def test_block_trailing_triple_string(): body = (' x = """This\n' 'is\n' '"probably"\n' '\'not\' what I meant.\n' '"""\n') s = SIMPLE_WITH + body glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_glb('b', glbs, body) def test_block_func_oneline(): body = ' x += 42\n' s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, body, FUNC_OBSG, FUNC_OBSL) def test_block_func_manylines(): body = (' ![echo wow mom]\n' '# bad place for a comment\n' ' x += 42\n') s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, body, FUNC_OBSG, FUNC_OBSL) def test_block_func_leading_comment(): # leading comments do not show up in block lines body = (' # I am a leading comment\n' ' x += 42\n') s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, ' x += 42\n', FUNC_OBSG, FUNC_OBSL) def test_block_func_trailing_comment(): # trailing comments show up in block lines body = (' x += 42\n' ' # I am a trailing comment\n') s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, body, FUNC_OBSG, FUNC_OBSL) def test_blockfunc__trailing_line_continuation(): body = (' x += \\\n' ' 42\n') s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, body, FUNC_OBSG, FUNC_OBSL) def test_block_func_trailing_close_paren(): body = (' x += int("42"\n' ' )\n') s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, body, FUNC_OBSG, FUNC_OBSL) def test_block_func_trailing_close_many(): body = (' x = {None: [int("42"\n' ' )\n' ' ]\n' ' }\n') s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, body, FUNC_OBSG, FUNC_OBSL) def test_block_func_trailing_triple_string(): body = (' x = """This\n' 'is\n' '"probably"\n' '\'not\' what I meant.\n' '"""\n') s = FUNC_WITH.format(body=body) glbs = {'Block': Block} check_exec(s, glbs=glbs, locs=None) block_checks_func('rtn', glbs, body, FUNC_OBSG, FUNC_OBSL) # # Functor tests # X2_WITH = ('{var} = 1\n' 'with! Functor() as f:\n' '{body}' '{var} += 1\n' '{calls}\n' ) def test_functor_oneline_onecall_class(): body = (' global y\n' ' y += 42\n') calls = 'f()' s = X2_WITH.format(body=body, calls=calls, var='y') glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'y': 44}) def test_functor_oneline_onecall_func(): body = (' global z\n' ' z += 42\n') calls = 'f.func()' s = X2_WITH.format(body=body, calls=calls, var='z') glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'z': 44}) def test_functor_oneline_onecall_both(): body = (' global x\n' ' x += 42\n') calls = 'f()\nf.func()' s = X2_WITH.format(body=body, calls=calls, var='x') glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'x': 86}) XA_WITH = ('x = [1]\n' 'with! Functor() as f:\n' '{body}' 'x.append(2)\n' '{calls}\n' ) def test_functor_oneline_append(): body = ' x.append(3)\n' calls = 'f()\n' s = XA_WITH.format(body=body, calls=calls) glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'x': [1, 2, 3]}) def test_functor_return(): body = ' x = 42' t = ('res = 0\n' 'with! Functor(rtn="x") as f:\n' '{body}\n' 'res = f()\n') s = t.format(body=body) glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'res': 42}) def test_functor_args(): body = ' x = 42 + a' t = ('res = 0\n' 'with! Functor(args=("a",), rtn="x") as f:\n' '{body}\n' 'res = f(2)\n') s = t.format(body=body) glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'res': 44}) def test_functor_kwargs(): body = ' x = 42 + a + b' t = ('res = 0\n' 'with! Functor(kwargs={{"a": 1, "b": 12}}, rtn="x") as f:\n' '{body}\n' 'res = f(b=6)\n') s = t.format(body=body) glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'res': 49}) def test_functor_fullsig(): body = ' x = 42 + a + b + c' t = ('res = 0\n' 'with! Functor(args=("c",), kwargs={{"a": 1, "b": 12}}, rtn="x") as f:\n' '{body}\n' 'res = f(55)\n') s = t.format(body=body) glbs = {'Functor': Functor} check_exec(s, glbs=glbs, locs=None) block_checks_glb('f', glbs, body, {'res': 110})