This commit is contained in:
Bob Hyman 2016-08-14 16:13:58 -04:00
commit e0fe044859
25 changed files with 352 additions and 109 deletions

View file

@ -474,7 +474,7 @@ result is automatically converted to a string. For example,
4
>>> echo @([42, 'yo'])
42 yo
>>> echo "hello" | @(lambda a, s=None: s.strip + " world")
>>> echo "hello" | @(lambda a, s=None: s.strip() + " world\n")
hello world
This syntax can be used inside of a captured or uncaptured subprocess, and can
@ -1104,8 +1104,9 @@ must have one of the following two signatures
return 0
Adding and Removing Aliases
---------------------------
Adding, Modifying, and Removing Aliases
---------------------------------------
We can dynamically alter the aliases present simply by modifying the
built-in mapping. Here is an example using a function value:
@ -1117,6 +1118,23 @@ built-in mapping. Here is an example using a function value:
>>> banana
'My spoon is tooo big!'
To redefine an alias, simply assign a new function, here using a python lambda
with keyword arguments:
.. code-block:: xonshcon
>>> aliases['banana'] = lambda args,stdin=None: "Banana for scale.\n"
>>> banana
Banana for scale.
Removing an alias is as easy as deleting the key from the alias dictionary:
.. code-block:: xonshcon
>>> del aliases['banana']
.. note::
Alias functions should generally be defined with a leading underscore.

View file

@ -0,0 +1,14 @@
**Added:** None
**Changed:** None
**Deprecated:** None
**Removed:** None
**Fixed:**
* Fix a startup problem on windows caused by a refactor of Prompt_toolkit.
https://github.com/jonathanslenders/python-prompt-toolkit/commit/a9df2a2
**Security:** None

View file

@ -0,0 +1,25 @@
**Added:**
* ``history show`` args ``-t``, ``-f``, ``-T`` ``+T`` to filter commands by timestamp
* ``ensure_timestamp`` in xonsh.tools to try and convert an object to a timestamp a.k.a float
* ``$XONSH_DATETIME_FORMAT`` envvar, the default format to be used with ``datetime.datetime.strptime()``
**Changed:**
* ``_hist_parse_args`` implementation refactor
* moved all parameter checking in ``_hist_get``
* ``_hist_show`` to handle numeration and timestamp printing of commands
**Deprecated:** None
**Removed:** None
**Fixed:**
* ``ensure_slice`` bugfix for -1 index/slice
**Security:** None

16
news/impacc.rst Normal file
View file

@ -0,0 +1,16 @@
**Added:** None
**Changed:**
* ``imphooks`` now checks directory access rights.
**Deprecated:** None
**Removed:** None
**Fixed:**
* Xonsh will no longer fail to start in directories where the user doesn't have
read access.
**Security:** None

21
news/imphook.rst Normal file
View file

@ -0,0 +1,21 @@
**Added:** None
**Changed:**
* ``xonsh.imphooks`` does not install the import hooks automatically, you now
need to explicitly call the `install_hook()` method defined in this module.
For example: ``from xonsh.imphooks import install_hook; install_hook()``. The
``install_hook`` method can safely be called several times. If you need
compatibility with previous versions of Xonsh you can use the following::
from xonsh import imphooks
getattr(imphooks, 'install_hook', lambda:None)()
**Deprecated:** None
**Removed:** None
**Fixed:** None
**Security:** None

13
news/lazy_union.rst Normal file
View file

@ -0,0 +1,13 @@
**Added:** None
**Changed:** None
**Deprecated:** None
**Removed:** None
**Fixed:**
* LazyObject supports set union
**Security:** None

13
news/pcrash.rst Normal file
View file

@ -0,0 +1,13 @@
**Added:** None
**Changed:** None
**Deprecated:** None
**Removed:** None
**Fixed:**
* Made pip completer more robust to when pip is not installed.
**Security:** None

View file

@ -1,6 +1,7 @@
[pytest]
flake8-max-line-length = 180
flake8-ignore =
*.py E122
*.py E402
tests/tools.py E128
xonsh/ast.py F401

View file

@ -178,6 +178,10 @@ def test_parser_show(args, exp):
'session': exp[1],
'slices': exp[2],
'numerate': exp[3],
'reverse': exp[4]}
'reverse': exp[4],
'start_time': None,
'end_time': None,
'datetime_format': None,
'timestamp': False}
ns = _hist_parse_args(shlex.split(args))
assert ns.__dict__ == exp_ns

View file

@ -2,13 +2,13 @@
"""Testing xonsh import hooks"""
import pytest
from xonsh import imphooks # noqa
from xonsh import built_ins
from xonsh import imphooks
from xonsh.environ import Env
from xonsh.execer import Execer
from xonsh.built_ins import load_builtins, unload_builtins
import builtins
imphooks.install_hook()
@pytest.yield_fixture(autouse=True)
def imp_env(xonsh_execer):

View file

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
"""Tests xonsh tools."""
import builtins
import datetime as dt
import os
import pathlib
from tempfile import TemporaryDirectory
import stat
import builtins
from tempfile import TemporaryDirectory
import pytest
@ -22,7 +23,8 @@ from xonsh.tools import (
subexpr_from_unbalanced, subproc_toks, to_bool, to_bool_or_int,
to_dynamic_cwd_tuple, to_logfile_opt, pathsep_to_set, set_to_pathsep,
is_string_seq, pathsep_to_seq, seq_to_pathsep, is_nonstring_seq_of_strings,
pathsep_to_upper_seq, seq_to_upper_pathsep, expandvars, is_int_as_str, is_slice_as_str
pathsep_to_upper_seq, seq_to_upper_pathsep, expandvars, is_int_as_str, is_slice_as_str,
ensure_timestamp,
)
from xonsh.commands_cache import CommandsCache
from xonsh.built_ins import expand_path
@ -816,6 +818,7 @@ def test_bool_or_int_to_str(inp, exp):
(42, slice(42, 43)),
(None, slice(None, None, None)),
(slice(1,2), slice(1,2)),
('-1', slice(-1, None, None)),
('42', slice(42, 43)),
('-42', slice(-42, -41)),
('1:2:3', slice(1, 2, 3)),
@ -1120,3 +1123,16 @@ def test_expandvars(inp, exp, xonsh_builtins):
env = Env({'foo':'bar', 'spam': 'eggs', 'a_bool': True, 'an_int': 42, 'none': None})
xonsh_builtins.__xonsh_env__ = env
assert expandvars(inp) == exp
@pytest.mark.parametrize('inp, fmt, exp',[
(572392800.0, None, 572392800.0),
('42.1459', None, 42.1459),
(dt.datetime(2016, 8, 2, 13, 24), None, dt.datetime(2016, 8, 2, 13, 24).timestamp()),
('2016-8-10 16:14', None, dt.datetime(2016, 8, 10, 16, 14).timestamp()),
('2016/8/10 16:14:40', '%Y/%m/%d %H:%M:%S', dt.datetime(2016, 8, 10, 16, 14, 40).timestamp()),
])
def test_ensure_timestamp(inp, fmt, exp, xonsh_builtins):
xonsh_builtins.__xonsh_env__['XONSH_DATETIME_FORMAT'] = '%Y-%m-%d %H:%M'
obs = ensure_timestamp(inp, fmt)
assert exp == obs

View file

@ -53,4 +53,16 @@ _foobar = 3
""")
ctx = xontrib_context('spameggs')
assert ctx == {'spam': 1, '_foobar': 3}
assert ctx == {'spam': 1, '_foobar': 3}
def test_xshxontrib(tmpmod):
"""
Test that .xsh xontribs are loadable
"""
with tmpmod.mkdir("xontrib").join("script.xsh").open('w') as x:
x.write("""
hello = 'world'
""")
ctx = xontrib_context('script')
assert ctx == {'hello': 'world'}

View file

@ -11,8 +11,11 @@ PIP_LIST_RE = xl.LazyObject(lambda: re.compile("pip(?:\d|\.)* (?:uninstall|show)
@xl.lazyobject
def ALL_COMMANDS():
help_text = str(subprocess.check_output(['pip', '--help'],
stderr=subprocess.DEVNULL))
try:
help_text = str(subprocess.check_output(['pip', '--help'],
stderr=subprocess.DEVNULL))
except FileNotFoundError:
return []
commands = re.findall(" (\w+) ", help_text)
return [c for c in commands if c not in ['completion', 'help']]
@ -24,7 +27,11 @@ def complete_pip(prefix, line, begidx, endidx, ctx):
(not PIP_RE.search(line)):
return
if PIP_LIST_RE.search(line):
items = subprocess.check_output(['pip', 'list'], stderr=subprocess.DEVNULL)
try:
items = subprocess.check_output(['pip', 'list'],
stderr=subprocess.DEVNULL)
except FileNotFoundError:
return set()
items = items.decode('utf-8').splitlines()
return set(i.split()[0] for i in items)

View file

@ -89,7 +89,10 @@ Ensurer.__doc__ = """Named tuples whose elements are functions that
represent environment variable validation, conversion, detyping.
"""
DEFAULT_ENSURERS = LazyObject(lambda: {
@lazyobject
def DEFAULT_ENSURERS():
return {
'AUTO_CD': (is_bool, to_bool, bool_to_str),
'AUTO_PUSHD': (is_bool, to_bool, bool_to_str),
'AUTO_SUGGEST': (is_bool, to_bool, bool_to_str),
@ -148,9 +151,9 @@ DEFAULT_ENSURERS = LazyObject(lambda: {
'XONSH_SHOW_TRACEBACK': (is_bool, to_bool, bool_to_str),
'XONSH_STORE_STDOUT': (is_bool, to_bool, bool_to_str),
'XONSH_STORE_STDIN': (is_bool, to_bool, bool_to_str),
'XONSH_TRACEBACK_LOGFILE': (is_logfile_opt, to_logfile_opt,
logfile_opt_to_str)
}, globals(), 'DEFAULT_ENSURERS')
'XONSH_TRACEBACK_LOGFILE': (is_logfile_opt, to_logfile_opt, logfile_opt_to_str),
'XONSH_DATETIME_FORMAT': (is_string, ensure_string, ensure_string),
}
#
@ -303,7 +306,8 @@ def DEFAULT_VALUES():
'XONSH_SHOW_TRACEBACK': False,
'XONSH_STORE_STDIN': False,
'XONSH_STORE_STDOUT': False,
'XONSH_TRACEBACK_LOGFILE': None
'XONSH_TRACEBACK_LOGFILE': None,
'XONSH_DATETIME_FORMAT': '%Y-%m-%d %H:%M',
}
if hasattr(locale, 'LC_MESSAGES'):
dv['LC_MESSAGES'] = locale.setlocale(locale.LC_MESSAGES)
@ -333,8 +337,11 @@ store_as_str : bool, optional
# iterates from back
VarDocs.__new__.__defaults__ = (True, DefaultNotGiven, False)
# Please keep the following in alphabetic order - scopatz
DEFAULT_DOCS = LazyObject(lambda: {
@lazyobject
def DEFAULT_DOCS():
return {
'ANSICON': VarDocs('This is used on Windows to set the title, '
'if available.', configurable=False),
'AUTO_CD': VarDocs(
@ -637,7 +644,10 @@ DEFAULT_DOCS = LazyObject(lambda: {
'XONSH_SHOW_TRACEBACK has been set. Its value must be a writable file '
'or None / the empty string if traceback logging is not desired. '
'Logging to a file is not enabled by default.'),
}, globals(), 'DEFAULT_DOCS')
'XONSH_DATETIME_FORMAT': VarDocs(
'The format that is used for ``datetime.strptime()`` in various places'
'i.e the history timestamp option'),
}
#

View file

@ -18,7 +18,7 @@ import collections.abc as abc
from xonsh.lazyasd import lazyobject
from xonsh.lazyjson import LazyJSON, ljdump, LJNode
from xonsh.tools import (ensure_slice, to_history_tuple,
expanduser_abs_path)
expanduser_abs_path, ensure_timestamp)
from xonsh.diff_history import _dh_create_parser, _dh_main_action
@ -343,14 +343,23 @@ def _hist_create_parser():
description='Tools for dealing with history')
subp = p.add_subparsers(title='action', dest='action')
# session action
show = subp.add_parser('show', help='displays session history, default action')
show = subp.add_parser('show', prefix_chars='-+',
help='displays session history, default action')
show.add_argument('-r', dest='reverse', default=False,
action='store_true', help='reverses the direction')
show.add_argument('-n', dest='numerate', default=False, action='store_true',
help='numerate each command')
show.add_argument('-t', dest='timestamp', default=False,
action='store_true', help='show command timestamps')
show.add_argument('-T', dest='end_time', default=None,
help='show only commands before timestamp')
show.add_argument('+T', dest='start_time', default=None,
help='show only commands after timestamp')
show.add_argument('-f', dest='datetime_format', default=None,
help='the datetime format to be used for filtering and printing')
show.add_argument('session', nargs='?', choices=_HIST_SESSIONS.keys(), default='session',
help='Choose a history session, defaults to current session')
show.add_argument('slices', nargs=argparse.REMAINDER, default=[],
show.add_argument('slices', nargs='*', default=None,
help='display history entries or range of entries')
# 'id' subcommand
subp.add_parser('id', help='displays the current session id')
@ -388,7 +397,7 @@ def _hist_create_parser():
def _hist_get_portion(commands, slices):
"""Yield from portions of history commands."""
if len(slices) == 1:
s = ensure_slice(slices[0])
s = slices[0]
try:
yield from itertools.islice(commands, s.start, s.stop, s.step)
return
@ -396,26 +405,17 @@ def _hist_get_portion(commands, slices):
pass
commands = list(commands)
for s in slices:
s = ensure_slice(s)
yield from commands[s]
def _hist_filter_ts(commands, start_time=None, end_time=None):
def _hist_filter_ts(commands, start_time, end_time):
"""Yield only the commands between start and end time."""
if start_time is None:
start_time = 0.0
elif isinstance(start_time, datetime.datetime):
start_time = start_time.timestamp()
if end_time is None:
end_time = float('inf')
elif isinstance(end_time, datetime.datetime):
end_time = end_time.timestamp()
for cmd in commands:
if start_time <= cmd[1] < end_time:
yield cmd
def _hist_get(session='session', slices=None,
def _hist_get(session='session', *, slices=None, datetime_format=None,
start_time=None, end_time=None, location=None):
"""Get the requested portion of shell history.
@ -437,8 +437,18 @@ def _hist_get(session='session', slices=None,
"""
cmds = _HIST_SESSIONS[session](location=location)
if slices:
# transform/check all slices
slices = [ensure_slice(s) for s in slices]
cmds = _hist_get_portion(cmds, slices)
if start_time or end_time:
if start_time is None:
start_time = 0.0
else:
start_time = ensure_timestamp(start_time, datetime_format)
if end_time is None:
end_time = float('inf')
else:
end_time = ensure_timestamp(end_time, datetime_format)
cmds = _hist_filter_ts(cmds, start_time, end_time)
return cmds
@ -447,18 +457,31 @@ def _hist_show(ns, *args, **kwargs):
"""Show the requested portion of shell history.
Accepts same parameters with `_hist_get`.
"""
commands = _hist_get(ns.session, ns.slices, **kwargs)
try:
if ns.reverse:
commands = reversed(list(commands))
if not ns.numerate:
for c, _, _ in commands:
print(c)
else:
for c, _, i in commands:
print('{}: {}'.format(i, c))
commands = _hist_get(ns.session,
slices=ns.slices,
start_time=ns.start_time,
end_time=ns.end_time,
datetime_format=ns.datetime_format)
except ValueError as err:
print("history: error: {}".format(err), file=sys.stderr)
return
if ns.reverse:
commands = reversed(list(commands))
if not ns.numerate and not ns.timestamp:
for c, _, _ in commands:
print(c)
elif not ns.timestamp:
for c, _, i in commands:
print('{}: {}'.format(i, c))
elif not ns.numerate:
for c, ts, _ in commands:
dt = datetime.datetime.fromtimestamp(ts).ctime()
print('({}) {}'.format(dt, c))
else:
for c, ts, i in commands:
dt = datetime.datetime.fromtimestamp(ts).ctime()
print('{}:({}) {}'.format(i, dt, c))
# Interface to History
@ -640,23 +663,28 @@ def _HIST_MAIN_ACTIONS():
def _hist_parse_args(args):
"""Parse arguments using the history argument parser."""
"""Prepare and parse arguments for the history command.
Add default action for ``history`` and
default session for ``history show``.
"""
parser = _hist_create_parser()
if not args:
args = ['show', 'session']
elif args[0] not in _HIST_MAIN_ACTIONS and args[0] not in ('-h', '--help'):
args = ['show', 'session'] + args
elif args[0] == 'show':
slices_index = 0
for i, a in enumerate(args[1:], 1):
if a in _HIST_SESSIONS:
break
elif a.startswith('-') and a.lstrip('-').isalpha():
# get last optional arg, before slices
slices_index = i
else: # no session arg found, insert before slices
args.insert(slices_index + 1, 'session')
return parser.parse_args(args)
if args[0] == 'show':
if not any(a in _HIST_SESSIONS for a in args):
args.insert(1, 'session')
ns, slices = parser.parse_known_args(args)
if slices:
if not ns.slices:
ns.slices = slices
else:
ns.slices.extend(slices)
else:
ns = parser.parse_args(args)
return ns
def history_main(args=None, stdin=None):

View file

@ -3,11 +3,11 @@
This module registers the hooks it defines when it is imported.
"""
import builtins
from importlib.abc import MetaPathFinder, SourceLoader
from importlib.machinery import ModuleSpec
import os
import sys
import builtins
from importlib.machinery import ModuleSpec
from importlib.abc import MetaPathFinder, SourceLoader
from xonsh.execer import Execer
from xonsh.platform import scandir
@ -48,7 +48,7 @@ class XonshImportHook(MetaPathFinder, SourceLoader):
for p in path:
if not isinstance(p, str):
continue
if not os.path.isdir(p):
if not os.path.isdir(p) or not os.access(p, os.R_OK):
continue
if fname not in (x.name for x in scandir(p)):
continue
@ -84,4 +84,14 @@ class XonshImportHook(MetaPathFinder, SourceLoader):
return code
sys.meta_path.append(XonshImportHook())
def install_hook():
"""
Install Xonsh import hook in `sys.metapath` in order for `.xsh` files to be
importable.
Can safely be called many times, will be no-op if a xonsh import hook is
already present.
"""
if XonshImportHook not in {type(hook) for hook in sys.meta_path}:
sys.meta_path.append(XonshImportHook())

View file

@ -112,6 +112,10 @@ class LazyObject(object):
obj = self._lazy_obj()
return hash(obj)
def __or__(self, other):
obj = self._lazy_obj()
return obj | other
def lazyobject(f):
"""Decorator for constructing lazy objects from a function."""

View file

@ -18,6 +18,7 @@ from xonsh.platform import HAS_PYGMENTS, ON_WINDOWS
from xonsh.codecache import run_script_with_cache, run_code_with_cache
from xonsh.xonfig import xonfig_main
from xonsh.lazyimps import pygments, pyghooks
from xonsh.imphooks import install_hook
def get_setproctitle():
@ -188,6 +189,7 @@ def premain(argv=None):
args.mode = XonshMode.interactive
shell_kwargs['completer'] = True
shell_kwargs['login'] = True
install_hook()
builtins.__xonsh_shell__ = Shell(**shell_kwargs)
env = builtins.__xonsh_env__
env['XONSH_LOGIN'] = shell_kwargs['login']

View file

@ -11,11 +11,10 @@ from xonsh.aliases import xonsh_exit
from xonsh.tools import ON_WINDOWS
env = builtins.__xonsh_env__
indent_ = env.get('INDENT')
DEDENT_TOKENS = frozenset(['raise', 'return', 'pass', 'break', 'continue'])
def carriage_return(b, cli):
def carriage_return(b, cli, *, autoindent=True):
"""
Preliminary parser to determine if 'Enter' key should send command to
the xonsh parser for execution or should insert a newline for continued
@ -29,35 +28,37 @@ def carriage_return(b, cli):
- Any text exists below cursor position (relevant when editing previous
multiline blocks)
"""
doc = b.document
at_end_of_line = _is_blank(doc.current_line_after_cursor)
current_line_blank = _is_blank(doc.current_line)
at_end_of_line = _is_blank(b.document.current_line_after_cursor)
current_line_blank = _is_blank(b.document.current_line)
indent = env.get('INDENT') if autoindent else ''
# indent after a colon
if (b.document.current_line_before_cursor.strip().endswith(':') and
if (doc.current_line_before_cursor.strip().endswith(':') and
at_end_of_line):
b.newline()
b.insert_text(indent_, fire_event=False)
b.newline(copy_margin=autoindent)
b.insert_text(indent, fire_event=False)
# if current line isn't blank, check dedent tokens
elif (not current_line_blank and
b.document.current_line.split(maxsplit=1)[0] in DEDENT_TOKENS and
b.document.line_count > 1):
b.newline(copy_margin=True)
_ = b.delete_before_cursor(count=len(indent_))
elif (not b.document.on_first_line and
doc.current_line.split(maxsplit=1)[0] in DEDENT_TOKENS and
doc.line_count > 1):
b.newline(copy_margin=autoindent)
b.delete_before_cursor(count=len(indent))
elif (not doc.on_first_line and
not current_line_blank):
b.newline(copy_margin=True)
elif (b.document.char_before_cursor == '\\' and
b.newline(copy_margin=autoindent)
elif (doc.char_before_cursor == '\\' and
not (not builtins.__xonsh_env__.get('FORCE_POSIX_PATHS')
and ON_WINDOWS)):
b.newline()
elif (b.document.find_next_word_beginning() is not None and
b.newline(copy_margin=autoindent)
elif (doc.find_next_word_beginning() is not None and
(any(not _is_blank(i)
for i
in b.document.lines_from_current[1:]))):
b.newline(copy_margin=True)
elif not current_line_blank and not can_compile(b.document.text):
b.newline()
in doc.lines_from_current[1:]))):
b.newline(copy_margin=autoindent)
elif not current_line_blank and not can_compile(doc.text):
b.newline(copy_margin=autoindent)
else:
b.accept_action.validate_and_handle(cli, b)

View file

@ -20,7 +20,9 @@ Implementations:
import builtins
import collections
import collections.abc as abc
import contextlib
import ctypes
import datetime
import functools
import glob
import os
@ -31,7 +33,6 @@ import sys
import threading
import traceback
import warnings
import contextlib
# adding further imports from xonsh modules is discouraged to avoid circular
# dependencies
@ -933,7 +934,10 @@ def ensure_slice(x):
return x
try:
x = int(x)
s = slice(x, x+1)
if x != -1:
s = slice(x, x+1)
else:
s = slice(-1, None, None)
except ValueError:
x = x.strip('[]()')
m = SLICE_REG.fullmatch(x)
@ -1271,7 +1275,10 @@ def _get_color_indexes(style_map):
for token in style_map:
attr = pt_style.token_to_attrs[token]
if attr.color is not None:
index = table.lookup_color(attr.color, attr.bgcolor)
try:
index = table.lookup_color(attr.color, attr.bgcolor)
except AttributeError:
index = table.lookup_fg_color(attr.color)
try:
rgb = (int(attr.color[0:2], 16),
int(attr.color[2:4], 16),
@ -1585,3 +1592,19 @@ def _iglobpath(s, ignore_case=False, sort_result=None):
def iglobpath(s, ignore_case=False, sort_result=None):
"""Simple wrapper around iglob that also expands home and env vars."""
return _iglobpath(s, ignore_case=ignore_case, sort_result=sort_result)[0]
def ensure_timestamp(t, datetime_format=None):
if isinstance(t, (int, float)):
return t
try:
return float(t)
except (ValueError, TypeError):
pass
if datetime_format is None:
datetime_format = builtins.__xonsh_env__['XONSH_DATETIME_FORMAT']
if isinstance(t, datetime.datetime):
t = t.timestamp()
else:
t = datetime.datetime.strptime(t, datetime_format).timestamp()
return t

View file

@ -281,8 +281,10 @@ def make_xonfig_wizard(default_file=None, confirm=False):
])
if confirm:
q = ("Would you like to run the xonsh configuration wizard now?\n\n"
"1. Yes\n2. No, but ask me later.\n3. No, and don't ask me again."
"\n\n1, 2, or 3 [default: 2]? ")
"1. Yes (You can abort at any time)\n"
"2. No, but ask me next time.\n"
"3. No, and don't ask me again.\n\n"
"1, 2, or 3 [default: 2]? ")
passer = wiz.Pass()
saver = wiz.Save(check=False, ask_filename=False,
default_file=default_file)

View file

@ -1,13 +1,15 @@
"""Hooks for the distributed parallel computing library."""
from xonsh.contexts import Functor
__all__ = 'DSubmitter', 'dsubmit'
def dworker(args, stdin=None):
"""Programatic access to the dworker utility, to allow launching
workers that also have access to xonsh builtins.
"""
from distributed.cli import dworker as _dworker
_dworker.main.main(args=args, prog_name='dworker', standalone_mode=False)
from distributed.cli import dworker
dworker.main.main(args=args, prog_name='dworker', standalone_mode=False)
aliases['dworker'] = dworker
@ -67,7 +69,3 @@ def dsubmit(*a, args=(), kwargs=None, rtn='', **kw):
e = Executor(*a, **kw)
dsub = DSubmitter(e, args=args, kwargs=kwargs, rtn=rtn)
return dsub
# some cleanup
del dworker, Functor

View file

@ -1,13 +1,15 @@
"""Matplotlib xontribution."""
from xonsh.proc import foreground as _foreground
from xonsh.proc import foreground as foreground
__all__ = ()
@_foreground
def _mpl(args, stdin=None):
@foreground
def mpl(args, stdin=None):
"""Hooks to matplotlib"""
from xontrib.mplhooks import show
show()
aliases['mpl'] = _mpl
aliases['mpl'] = mpl

View file

@ -1,11 +1,13 @@
"""Python virtual environment manager for xonsh."""
import sys as _sys
import xontrib.voxapi as _voxapi
import xonsh.lazyasd as _lazyasd
import sys
import xontrib.voxapi as voxapi
import xonsh.lazyasd as lazyasd
__all__ = ()
class _VoxHandler:
class VoxHandler:
"""Vox is a virtual environment manager for xonsh."""
def parser():
@ -57,7 +59,7 @@ class _VoxHandler:
subparsers.add_parser('help', help='Show this help message')
return parser
parser = _lazyasd.LazyObject(parser, locals(), 'parser')
parser = lazyasd.LazyObject(parser, locals(), 'parser')
aliases = {
'create': 'new',
@ -71,7 +73,7 @@ class _VoxHandler:
}
def __init__(self):
self.vox = _voxapi.Vox()
self.vox = voxapi.Vox()
def __call__(self, args, stdin=None):
"""Call the right handler method for a given command."""
@ -98,7 +100,7 @@ class _VoxHandler:
try:
self.vox.activate(args.name)
except KeyError:
print('This environment doesn\'t exist. Create it with "vox new %s".\n' % name, file=_sys.stderr)
print('This environment doesn\'t exist. Create it with "vox new %s".\n' % name, file=sys.stderr)
return None
else:
print('Activated "%s".\n' % args.name)
@ -107,7 +109,7 @@ class _VoxHandler:
"""Deactive the active virtual environment."""
if self.vox.active() is None:
print('No environment currently active. Activate one with "vox activate".\n', file=_sys.stderr)
print('No environment currently active. Activate one with "vox activate".\n', file=sys.stderr)
return None
env_name = self.vox.deactivate()
print('Deactivated "%s".\n' % env_name)
@ -122,7 +124,7 @@ class _VoxHandler:
return None
if not envs:
print('No environments available. Create one with "vox new".\n', file=_sys.stderr)
print('No environments available. Create one with "vox new".\n', file=sys.stderr)
return None
print('Available environments:')
@ -134,9 +136,9 @@ class _VoxHandler:
for name in args.names:
try:
del self.vox[name]
except _voxapi.EnvironmentInUse:
except voxapi.EnvironmentInUse:
print('The "%s" environment is currently active. In order to remove it, deactivate it first with "vox deactivate %s".\n' % (name, name),
file=_sys.stderr)
file=sys.stderr)
return
else:
print('Environment "%s" removed.' % name)
@ -152,4 +154,4 @@ class _VoxHandler:
return vox(args, stdin=stdin)
aliases['vox'] = _VoxHandler.handle
aliases['vox'] = VoxHandler.handle

View file

@ -7,6 +7,7 @@ import collections.abc
from xonsh.platform import ON_POSIX, ON_WINDOWS, scandir
VirtualEnvironment = collections.namedtuple('VirtualEnvironment', ['env', 'bin'])