seem to have working execer

This commit is contained in:
Anthony Scopatz 2015-02-11 02:01:35 -06:00
parent 4011a3eb9e
commit 5d64d4492f
5 changed files with 72 additions and 30 deletions

View file

@ -6,6 +6,8 @@ import ast
from xonsh.execer import Execer
from tools import mock_xonsh_env
DEBUG_LEVEL = 0
EXECER = None
@ -16,15 +18,21 @@ def setup():
def check_exec(input):
if not input.endswith('\n'):
input += '\n'
EXECER.debug_level = DEBUG_LEVEL
EXECER.exec(input)
with mock_xonsh_env(None):
if not input.endswith('\n'):
input += '\n'
EXECER.debug_level = DEBUG_LEVEL
EXECER.exec(input)
def test_bin_ls():
yield check_exec, '/bin/ls -l'
def test_ls_dashl():
yield check_exec, 'ls -l'
def test_which_ls():
yield check_exec, 'which ls'
if __name__ == '__main__':
nose.runmodule()

View file

@ -17,6 +17,8 @@ from ply.lex import LexToken
from xonsh.parser import Parser
from tools import mock_xonsh_env
PARSER = None
DEBUG_LEVEL = 0
#DEBUG_LEVEL = 100
@ -68,19 +70,10 @@ def check_stmts(input, run=True):
check_ast(input, run=run)
def check_xonsh_ast(xenv, input, run=True):
builtins.__xonsh_env__ = xenv
builtins.__xonsh_help__ = lambda x: x
builtins.__xonsh_superhelp__ = lambda x: x
builtins.__xonsh_regexpath__ = lambda x: []
builtins.__xonsh_subproc__ = subprocess
obs = PARSER.parse(input, debug_level=DEBUG_LEVEL)
if run:
exec(compile(obs, '<test>', 'exec'))
del builtins.__xonsh_env__
del builtins.__xonsh_help__
del builtins.__xonsh_superhelp__
del builtins.__xonsh_regexpath__
del builtins.__xonsh_subproc__
with mock_xonsh_env(xenv):
obs = PARSER.parse(input, debug_level=DEBUG_LEVEL)
if run:
exec(compile(obs, '<test>', 'exec'))
def check_xonsh(xenv, input, run=True):
if not input.endswith('\n'):

20
tests/tools.py Normal file
View file

@ -0,0 +1,20 @@
"""Tests the xonsh lexer."""
from __future__ import unicode_literals, print_function
import builtins
import subprocess
from contextlib import contextmanager
@contextmanager
def mock_xonsh_env(xenv):
builtins.__xonsh_env__ = xenv
builtins.__xonsh_help__ = lambda x: x
builtins.__xonsh_superhelp__ = lambda x: x
builtins.__xonsh_regexpath__ = lambda x: []
builtins.__xonsh_subproc__ = subprocess
yield
del builtins.__xonsh_env__
del builtins.__xonsh_help__
del builtins.__xonsh_superhelp__
del builtins.__xonsh_regexpath__
del builtins.__xonsh_subproc__

View file

@ -9,7 +9,7 @@ from ast import Module, Num, Expr, Str, Bytes, UnaryOp, UAdd, USub, Invert, \
Del, Pass, Raise, Import, alias, ImportFrom, Continue, Break, Yield, \
YieldFrom, Return, IfExp, Lambda, arguments, arg, Call, keyword, \
Attribute, Global, Nonlocal, If, While, For, withitem, With, Try, \
ExceptHandler, FunctionDef, ClassDef, Starred, NodeTransformer
ExceptHandler, FunctionDef, ClassDef, Starred, NodeTransformer, dump
from xonsh.tools import subproc_line
@ -17,12 +17,14 @@ def leftmostname(node):
"""Attempts to find the first name in the tree."""
if isinstance(node, Name):
rtn = node.id
elif isinstance(node, (Str, Bytes)):
rtn = node.s
#elif isinstance(node, (Str, Bytes)):
# rtn = node.s
elif isinstance(node, (BinOp, Compare)):
rtn = leftmostname(node.left)
elif isinstance(node, (Attribute, Subscript, Starred)):
elif isinstance(node, (Attribute, Subscript, Starred, Expr)):
rtn = leftmostname(node.value)
elif isinstance(node, Call):
rtn = leftmostname(node.func)
else:
rtn = None
return rtn
@ -89,12 +91,15 @@ class CtxAwareTransformer(NodeTransformer):
break
if inscope:
return node
newline = subproc_line(self.lines[node.lineno])
spline = subproc_line(self.lines[node.lineno - 1])
try:
node = self.parser.parse(newline)
newnode = self.parser.parse(spline)
newnode = newnode.body[0] # take the first (and only) Expr
newnode.lineno = node.lineno
newnode.col_offset = node.col_offset
except SyntaxError as e:
pass
return node
newnode = node
return newnode
def visit_Assign(self, node):
for targ in node.targets:
@ -138,12 +143,16 @@ class CtxAwareTransformer(NodeTransformer):
def visit_FunctionDef(self, node):
self.ctxadd(node.name)
self.contexts.append(set())
self.generic_visit(node)
self.contexts.pop()
return node
def visit_ClassDef(self, node):
self.ctxadd(node.name)
self.contexts.append(set())
self.generic_visit(node)
self.contexts.pop()
return node
def visit_Delete(self, node):
@ -159,3 +168,8 @@ class CtxAwareTransformer(NodeTransformer):
self.ctxadd(handler.name)
self.generic_visit(node)
return node
def visit_Global(self, node):
self.contexts[1].update(node.names) # contexts[1] is the global ctx
self.generic_visit(node)
return node

View file

@ -2,6 +2,8 @@
from __future__ import print_function, unicode_literals
import re
import os
import inspect
import builtins
from collections import Iterable, Sequence, Mapping
from xonsh import ast
@ -36,6 +38,7 @@ class Execer(object):
ctx = set()
elif isinstance(ctx, Mapping):
ctx = set(ctx.keys())
# Parsing actually happens in a couple of phases. The first is a
# shortcut for a context-free parser. Nomrally, all subprocess
# lines should be wrapped in $(), to indicate that they are a
@ -61,11 +64,16 @@ class Execer(object):
tree = self.ctxtransformer.ctxvisit(tree, input, ctx)
return tree
def exec(self, input, globals=None, locals=None):
def exec(self, input, glbs=None, locs=None, stacklevel=1):
"""Execute xonsh code."""
tree = self.parse(input, locals)
if glbs is None or locs is None:
frame = inspect.stack()[stacklevel][0]
glbs = frame.f_globals if glbs is None else glbs
locs = frame.f_locals if locs is None else locs
ctx = set(dir(builtins)) | set(glbs.keys()) | set(locs.keys())
tree = self.parse(input, ctx)
code = compile(tree, self.filename, 'exec')
#exec(code, globals, locals)
exec(code, glbs, locs)
def _parse_ctx_free(self, input):
last_error_line = -1
@ -84,4 +92,3 @@ class Execer(object):
lines[idx] = subproc_line(lines[idx])
input = '\n'.join(lines)
return tree