Merge branch 'master' into timeit

This commit is contained in:
Anthony Scopatz 2015-04-16 20:28:15 -05:00
commit eeb2c5c03d
10 changed files with 156 additions and 63 deletions

19
docs/aliases.rst Normal file
View file

@ -0,0 +1,19 @@
.. _aliases:
********************
Aliases
********************
xonsh builtin aliases.
xexec
====================
xexec uses the ``os.execvpe()`` function to replace the xonsh process with
the specified program. This provides the functionality of the bash ``exec``
builtin.
.. code-block:: bash
>>> xexec bash
bash $

View file

@ -1,6 +1,6 @@
package:
name: xonsh
version: "0.1.4"
version: "0.1.5"
source:
fn: xonsh.tar.gz

View file

@ -481,20 +481,26 @@ def test_setcomp_if_setcomp_if():
def test_dictcomp():
yield check_ast, '{x: x for x in "mom"}'
def test_dictcomp_unpack_parens():
yield check_ast, '{k: v for (k, v) in {"x": 42}.items()}'
def test_dictcomp_unpack_no_parens():
yield check_ast, '{k: v for k, v in {"x": 42}.items()}'
def test_dictcomp_if():
yield check_ast, '{x:x for x in "mom" if True}'
yield check_ast, '{x: x for x in "mom" if True}'
def test_dictcomp_if_and():
yield check_ast, '{x:x for x in "mom" if True and x == "m"}'
yield check_ast, '{x: x for x in "mom" if True and x == "m"}'
def test_dbl_dictcomp():
yield check_ast, '{x:y for x in "mom" for y in "dad"}'
yield check_ast, '{x: y for x in "mom" for y in "dad"}'
def test_dictcomp_if_dictcomp():
yield check_ast, '{x:y for x in "mom" if True for y in "dad"}'
yield check_ast, '{x: y for x in "mom" if True for y in "dad"}'
def test_dictcomp_if_dictcomp_if():
yield check_ast, '{x:y for x in "mom" if True for y in "dad" if y == "d"}'
yield check_ast, '{x: y for x in "mom" if True for y in "dad" if y == "d"}'
def test_lambda():
yield check_ast, 'lambda: 42'

View file

@ -1 +1 @@
__version__ = '0.1.4'
__version__ = '0.1.5'

View file

@ -9,37 +9,10 @@ import itertools
import subprocess
from warnings import warn
from xonsh.dirstack import dirs, pushd, popd
from xonsh.dirstack import cd, pushd, popd, dirs
from xonsh.jobs import jobs, fg, bg, kill_all_jobs
def cd(args, stdin=None):
"""Changes the directory.
If no directory is specified (i.e. if `args` is None) then this
changes to the current user's home directory.
"""
env = builtins.__xonsh_env__
cur_oldpwd = env.get('OLDPWD', os.getcwd())
if len(args) == 0:
d = os.path.expanduser('~')
elif len(args) == 1:
d = os.path.expanduser(args[0])
if d == '-':
d = cur_oldpwd
else:
return '', 'cd takes 0 or 1 arguments, not {0}\n'.format(len(args))
if not os.path.exists(d):
return '', 'cd: no such file or directory: {0}\n'.format(d)
if not os.path.isdir(d):
return '', 'cd: {0} is not a directory\n'.format(d)
env['OLDPWD'] = os.getcwd()
os.chdir(d)
env['PWD'] = os.getcwd()
return None, None
def exit(args, stdin=None): # pylint:disable=redefined-builtin,W0622
"""Sends signal to exit shell."""
builtins.__xonsh_exit__ = True
@ -115,6 +88,22 @@ def source_bash(args, stdin=None):
return
def xexec(args, stdin=None):
"""
Replaces current process with command specified and passes in the
current xonsh environment.
"""
env = builtins.__xonsh_env__
denv = env.detype()
if (len(args) > 0):
try:
os.execvpe(args[0], args, denv)
except FileNotFoundError as e:
return "xonsh: " + e.args[1] + ": " + args[0] + "\n"
else:
return "xonsh: exec: no args specified\n"
def bash_aliases():
"""Computes a dictionary of aliases based on Bash's aliases."""
try:
@ -150,6 +139,7 @@ DEFAULT_ALIASES = {
'EOF': exit,
'exit': exit,
'quit': exit,
'xexec': xexec,
'source-bash': source_bash,
'grep': ['grep', '--color=auto'],
'scp-resume': ['rsync', '--partial', '-h', '--progress', '--rsh=ssh'],

View file

@ -4,7 +4,6 @@ not to be confused with the special Python builtins module.
import os
import re
import sys
import time
import shlex
import signal
import locale
@ -22,7 +21,7 @@ from xonsh.tools import suggest_commands, XonshError
from xonsh.inspectors import Inspector
from xonsh.environ import default_env
from xonsh.aliases import DEFAULT_ALIASES, bash_aliases
from xonsh.jobs import print_one_job, get_next_job_number, wait_for_active_job
from xonsh.jobs import add_job, wait_for_active_job
from xonsh.jobs import ProcProxy
ENV = None
@ -508,21 +507,14 @@ def run_subproc(cmds, captured=True):
prev_proc = proc
for proc in procs[:-1]:
proc.stdout.close()
num = get_next_job_number()
pids = [i.pid for i in procs]
if not isinstance(prev_proc, ProcProxy):
builtins.__xonsh_active_job__ = num
builtins.__xonsh_all_jobs__[num] = {
add_job({
'cmds': cmds,
'pids': pids,
'pids': [i.pid for i in procs],
'obj': prev_proc,
'started': time.time(),
'pgrp': os.getpgid(prev_proc.pid),
'status': 'running',
'bg': background
}
})
if background:
print_one_job(num)
return
wait_for_active_job()
if write_target is None:

View file

@ -10,6 +10,73 @@ A list containing the currently remembered directories.
"""
def _get_cwd():
try:
return os.getcwd()
except (OSError, FileNotFoundError):
return None
def _change_working_directory(newdir):
env = builtins.__xonsh_env__
old = _get_cwd()
try:
os.chdir(newdir)
except (OSError, FileNotFoundError):
return
new = _get_cwd()
if old is not None:
env['OLDPWD'] = old
if new is not None:
env['PWD'] = new
def cd(args, stdin=None):
"""Changes the directory.
If no directory is specified (i.e. if `args` is None) then this
changes to the current user's home directory.
"""
env = builtins.__xonsh_env__
oldpwd = env.get('OLDPWD', None)
cwd = _get_cwd()
if len(args) == 0:
d = os.path.expanduser('~')
elif len(args) == 1:
d = os.path.expanduser(args[0])
if not os.path.isdir(d):
if d == '-':
if oldpwd is not None:
d = oldpwd
else:
return '', 'cd: no previous directory stored\n'
elif d.startswith('-'):
try:
num = int(d[1:])
except ValueError:
return '', 'cd: Invalid destination: {0}\n'.format(d)
if num == 0:
return
elif num < 0:
return '', 'cd: Invalid destination: {0}\n'.format(d)
elif num > len(DIRSTACK):
e = 'cd: Too few elements in dirstack ({0} elements)\n'
return '', e.format(len(DIRSTACK))
else:
d = DIRSTACK[num - 1]
else:
return '', 'cd takes 0 or 1 arguments, not {0}\n'.format(len(args))
if not os.path.exists(d):
return '', 'cd: no such file or directory: {0}\n'.format(d)
if not os.path.isdir(d):
return '', 'cd: {0} is not a directory\n'.format(d)
# now, push the directory onto the dirstack if AUTO_PUSHD is set
if cwd is not None and env.get('AUTO_PUSHD', False):
pushd(['-n', '-q', cwd])
_change_working_directory(os.path.abspath(d))
return None, None
def pushd(args, stdin=None):
"""
xonsh command: pushd
@ -71,16 +138,12 @@ def pushd(args, stdin=None):
e = 'Invalid argument to pushd: {0}\n'
return None, e.format(args.dir)
if new_pwd is not None:
e = None
if args.cd:
DIRSTACK.insert(0, os.path.expanduser(pwd))
_, e = builtins.default_aliases['cd']([new_pwd], None)
_change_working_directory(os.path.abspath(new_pwd))
else:
DIRSTACK.insert(0, os.path.expanduser(os.path.abspath(new_pwd)))
if e is not None:
return None, e
maxsize = env.get('DIRSTACK_SIZE', 20)
if len(DIRSTACK) > maxsize:
DIRSTACK = DIRSTACK[:maxsize]
@ -152,10 +215,7 @@ def popd(args, stdin=None):
if new_pwd is not None:
e = None
if args.cd:
_, e = builtins.default_aliases['cd']([new_pwd], None)
if e is not None:
return None, e
_change_working_directory(os.path.abspath(new_pwd))
if not args.quiet and not env.get('PUSHD_SILENT', False):
return dirs([], None)

View file

@ -12,6 +12,7 @@ from warnings import warn
from xonsh import __version__ as XONSH_VERSION
from xonsh.tools import TERM_COLORS
from xonsh.dirstack import _get_cwd
def current_branch(cwd=None, pad=True):
@ -20,7 +21,9 @@ def current_branch(cwd=None, pad=True):
bust should be extended in the future.
"""
branch = None
cwd = os.getcwd() if cwd is None else cwd
cwd = _get_cwd() if cwd is None else cwd
if cwd is None:
return ''
# step out completely if git is not installed
try:
@ -64,7 +67,7 @@ def current_branch(cwd=None, pad=True):
if pad and branch is not None:
branch = ' ' + branch
return branch
return branch or ''
DEFAULT_PROMPT = ('{BOLD_GREEN}{user}@{hostname}{BOLD_BLUE} '
@ -78,7 +81,7 @@ def _replace_home(x):
FORMATTER_DICT = dict(user=os.environ.get('USER', '<user>'),
hostname=socket.gethostname().split('.', 1)[0],
cwd=lambda: _replace_home(builtins.__xonsh_env__['PWD']),
curr_branch=lambda: current_branch() or '',
curr_branch=lambda: current_branch(),
**TERM_COLORS)
_formatter = string.Formatter()

View file

@ -3,6 +3,7 @@ Job control for the xonsh shell.
"""
import os
import sys
import time
import signal
import builtins
from collections import namedtuple
@ -56,7 +57,10 @@ def _give_terminal_to(pgid):
def print_one_job(num):
"""Print a line describing job number ``num``."""
job = builtins.__xonsh_all_jobs__[num]
try:
job = builtins.__xonsh_all_jobs__[num]
except KeyError:
return
act = '*' if num == builtins.__xonsh_active_job__ else ' '
status = job['status']
cmd = [' '.join(i) if isinstance(i, list) else i for i in job['cmds']]
@ -76,6 +80,23 @@ def get_next_job_number():
return i
def add_job(info):
"""
Add a new job to the jobs dictionary.
"""
info['started'] = time.time()
info['status'] = 'running'
try:
info['pgrp'] = os.getpgid(info['obj'].pid)
except ProcessLookupError:
return
num = get_next_job_number()
builtins.__xonsh_all_jobs__[num] = info
builtins.__xonsh_active_job__ = num
if info['bg']:
print_one_job(num)
def _default_sigint_handler(num, frame):
raise KeyboardInterrupt

View file

@ -2045,9 +2045,11 @@ class Parser(object):
def p_comp_for(self, p):
"""comp_for : FOR exprlist IN or_test comp_iter_opt"""
targs, it, p5 = p[2], p[4], p[5]
if len(targs) != 1:
assert False
targ = targs[0]
if len(targs) == 1:
targ = targs[0]
else:
targ = ensure_has_elts(targs, lineno=self.lineno,
col_offset=self.col)
store_ctx(targ)
comp = ast.comprehension(target=targ, iter=it, ifs=[])
comps = [comp]