mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
seem to have working execer
This commit is contained in:
parent
4011a3eb9e
commit
5d64d4492f
5 changed files with 72 additions and 30 deletions
|
@ -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()
|
||||
|
|
|
@ -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
20
tests/tools.py
Normal 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__
|
||||
|
30
xonsh/ast.py
30
xonsh/ast.py
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue