mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
Merge branch 'master' into pytest_migration
This commit is contained in:
commit
ba6f63f143
18 changed files with 593 additions and 139 deletions
|
@ -158,7 +158,7 @@ Dependencies
|
|||
|
||||
Prep your environment for running the tests::
|
||||
|
||||
$ pip install requirements-tests.txt
|
||||
$ pip install -r requirements-tests.txt
|
||||
|
||||
|
||||
----------------------------------
|
||||
|
|
14
news/path34.rst
Normal file
14
news/path34.rst
Normal file
|
@ -0,0 +1,14 @@
|
|||
**Added:** None
|
||||
|
||||
**Changed:** None
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
**Removed:** None
|
||||
|
||||
**Fixed:**
|
||||
|
||||
* No longer raises an error if a directory in ``$PATH`` does not exist on
|
||||
Python v3.4.
|
||||
|
||||
**Security:** None
|
13
news/rmenv.rst
Normal file
13
news/rmenv.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
**Added:** None
|
||||
|
||||
**Changed:** None
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
**Removed:**
|
||||
|
||||
* Removed the ``xonsh.built_ins.ENV`` global instance of the Env class.
|
||||
|
||||
**Fixed:** None
|
||||
|
||||
**Security:** None
|
15
news/sortglob.rst
Normal file
15
news/sortglob.rst
Normal file
|
@ -0,0 +1,15 @@
|
|||
**Added:**
|
||||
|
||||
* The results of glob expressions are sorted if ``$GLOB_SORTED`` is set.
|
||||
|
||||
**Changed:**
|
||||
|
||||
* ``GLOB_SORTED`` is enabled by default.
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
**Removed:** None
|
||||
|
||||
**Fixed:** None
|
||||
|
||||
**Security:** None
|
16
news/sub.rst
Normal file
16
news/sub.rst
Normal file
|
@ -0,0 +1,16 @@
|
|||
**Added:**
|
||||
|
||||
* LazyObjects will now load themselves on ``__getitem__()``
|
||||
|
||||
**Changed:** None
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
**Removed:** None
|
||||
|
||||
**Fixed:**
|
||||
|
||||
* Bug with setting hist size not being settable due to lazy object loading
|
||||
has been resolved.
|
||||
|
||||
**Security:** None
|
|
@ -55,7 +55,6 @@ def test_eval_recursive_callable_partial(xonsh_builtins):
|
|||
xonsh_builtins.__xonsh_env__ = Env(HOME=os.path.expanduser('~'))
|
||||
assert ALIASES.get('indirect_cd')(['arg2', 'arg3']) == ['..', 'arg2', 'arg3']
|
||||
|
||||
|
||||
class TestWhich:
|
||||
# Tests for the _whichgen function which is the only thing we
|
||||
# use from the _which.py module.
|
||||
|
|
|
@ -23,11 +23,11 @@ def test_reglob_tests():
|
|||
for f in testfiles:
|
||||
assert (f.startswith('test_'))
|
||||
|
||||
@pytest.fixture
|
||||
def env():
|
||||
e = Env(HOME=os.path.expanduser('~'))
|
||||
built_ins.ENV = e
|
||||
return e
|
||||
# @pytest.fixture
|
||||
# def env():
|
||||
# e = Env(HOME=os.path.expanduser('~'))
|
||||
# built_ins.ENV = e
|
||||
# return e
|
||||
|
||||
|
||||
@skip_if_on_windows
|
||||
|
|
|
@ -4,13 +4,14 @@ from __future__ import unicode_literals, print_function
|
|||
|
||||
from xonsh import imphooks # noqa
|
||||
from xonsh import built_ins
|
||||
from xonsh.environ import Env
|
||||
from xonsh.execer import Execer
|
||||
from xonsh.built_ins import load_builtins, unload_builtins
|
||||
|
||||
from tools import mock_xonsh_env
|
||||
LOADED_HERE = False
|
||||
|
||||
IMP_ENV = {'PATH': [], 'PATHEXT': []}
|
||||
IMP_ENV = Env({'PATH': [], 'PATHEXT': []})
|
||||
|
||||
def setup_module():
|
||||
global LOADED_HERE
|
||||
|
|
11
tests/test_lazyasd.py
Normal file
11
tests/test_lazyasd.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
"""Tests lazy and self destruictive objects."""
|
||||
from xonsh.lazyasd import LazyObject
|
||||
|
||||
#
|
||||
# LazyObject Tests
|
||||
#
|
||||
|
||||
def test_lazyobject_getitem():
|
||||
lo = LazyObject(lambda: {'x': 1}, {}, 'lo')
|
||||
assert 1 == lo['x']
|
||||
|
|
@ -10,7 +10,7 @@ import pytest
|
|||
from xonsh.ast import pdump
|
||||
from xonsh.parser import Parser
|
||||
|
||||
from tools import (mock_xonsh_env, VER_FULL, skip_if_py34)
|
||||
from tools import VER_FULL, skip_if_py34
|
||||
|
||||
PARSER = None
|
||||
DEBUG_LEVEL = 0
|
||||
|
@ -1518,31 +1518,44 @@ def test_async_await():
|
|||
# Xonsh specific syntax
|
||||
#
|
||||
|
||||
def test_dollar_name():
|
||||
check_xonsh_ast({'WAKKA': 42}, '$WAKKA')
|
||||
@pytest.mark.parametrize('env, inp', [
|
||||
# dollar
|
||||
({'WAKKA': 42}, '$WAKKA'), # name
|
||||
({'WAKKA': 42}, '${None or "WAKKA"}'), # py test
|
||||
({'WAKKA': 42, 'JAWAKA': 'WAKKA'}, '${$JAWAKA}'), # py recursive name
|
||||
({'WAKKA': 42, 'JAWAKA': 'WAKKA'}, '${None or $JAWAKA}'), # py test recursive name
|
||||
({'WAKKA': 42, 'JAWAKA': 'WAKKA'}, '${${"JAWA" + $JAWAKA[-2:]}}'), # py test recursive test
|
||||
])
|
||||
def test_xonsh_ast(env, inp, xonsh_builtins, run=True, mode='eval'):
|
||||
__tracebackhide__ = True
|
||||
xonsh_builtins.__xonsh_env__ = env
|
||||
obs = PARSER.parse(inp, debug_level=DEBUG_LEVEL)
|
||||
if obs is None:
|
||||
return # comment only
|
||||
bytecode = compile(obs, '<test-xonsh-ast>', mode)
|
||||
if run:
|
||||
exec(bytecode)
|
||||
|
||||
def test_question():
|
||||
check_xonsh_ast({}, 'range?')
|
||||
|
||||
def test_dobquestion():
|
||||
check_xonsh_ast({}, 'range??')
|
||||
|
||||
def test_question_chain():
|
||||
check_xonsh_ast({}, 'range?.index?')
|
||||
|
||||
|
||||
def test_dollar_py():
|
||||
check_xonsh({'WAKKA': 42}, 'x = "WAKKA"; y = ${x}')
|
||||
|
||||
def test_dollar_py_test():
|
||||
check_xonsh_ast({'WAKKA': 42}, '${None or "WAKKA"}')
|
||||
|
||||
def test_dollar_py_recursive_name():
|
||||
check_xonsh_ast({'WAKKA': 42, 'JAWAKA': 'WAKKA'}, '${$JAWAKA}')
|
||||
|
||||
def test_dollar_py_test_recursive_name():
|
||||
check_xonsh_ast({'WAKKA': 42, 'JAWAKA': 'WAKKA'}, '${None or $JAWAKA}')
|
||||
|
||||
def test_dollar_py_test_recursive_test():
|
||||
check_xonsh_ast({'WAKKA': 42, 'JAWAKA': 'WAKKA'},
|
||||
'${${"JAWA" + $JAWAKA[-2:]}}')
|
||||
|
||||
def test_dollar_name_set():
|
||||
check_xonsh({'WAKKA': 42}, '$WAKKA = 42')
|
||||
|
||||
def test_dollar_py_set():
|
||||
check_xonsh({'WAKKA': 42}, 'x = "WAKKA"; ${x} = 65')
|
||||
|
||||
|
||||
def test_dollar_sub():
|
||||
check_xonsh_ast({}, '$(ls)', False)
|
||||
|
||||
|
@ -1561,9 +1574,6 @@ def test_nested_madness():
|
|||
def test_ls_dot_nesting():
|
||||
check_xonsh_ast({}, '$(ls @(None or "."))', False)
|
||||
|
||||
def test_ls_dot_nesting_var():
|
||||
check_xonsh({}, 'x = "."; $(ls @(None or x))', False)
|
||||
|
||||
def test_ls_dot_str():
|
||||
check_xonsh_ast({}, '$(ls ".")', False)
|
||||
|
||||
|
@ -1591,9 +1601,6 @@ def test_bang_ls_dot():
|
|||
def test_bang_ls_dot_nesting():
|
||||
check_xonsh_ast({}, '!(ls @(None or "."))', False)
|
||||
|
||||
def test_bang_ls_dot_nesting_var():
|
||||
check_xonsh({}, 'x = "."; !(ls @(None or x))', False)
|
||||
|
||||
def test_bang_ls_dot_str():
|
||||
check_xonsh_ast({}, '!(ls ".")', False)
|
||||
|
||||
|
@ -1609,15 +1616,6 @@ def test_bang_ls_envvar_strval():
|
|||
def test_bang_ls_envvar_listval():
|
||||
check_xonsh_ast({'WAKKA': ['.', '.']}, '!(ls $WAKKA)', False)
|
||||
|
||||
def test_question():
|
||||
check_xonsh_ast({}, 'range?')
|
||||
|
||||
def test_dobquestion():
|
||||
check_xonsh_ast({}, 'range??')
|
||||
|
||||
def test_question_chain():
|
||||
check_xonsh_ast({}, 'range?.index?')
|
||||
|
||||
def test_ls_regex():
|
||||
check_xonsh_ast({}, '$(ls `[Ff]+i*LE` -l)', False)
|
||||
|
||||
|
@ -1699,14 +1697,6 @@ def test_bang_git_quotes_no_space():
|
|||
def test_bang_git_quotes_space():
|
||||
check_xonsh_ast({}, '![git commit -am "wakka jawaka"]', False)
|
||||
|
||||
def test_bang_git_two_quotes_space():
|
||||
check_xonsh({}, '![git commit -am "wakka jawaka"]\n'
|
||||
'![git commit -am "flock jawaka"]\n', False)
|
||||
|
||||
def test_bang_git_two_quotes_space_space():
|
||||
check_xonsh({}, '![git commit -am "wakka jawaka" ]\n'
|
||||
'![git commit -am "flock jawaka milwaka" ]\n', False)
|
||||
|
||||
def test_bang_ls_quotes_3_space():
|
||||
check_xonsh_ast({}, '![ls "wakka jawaka baraka"]', False)
|
||||
|
||||
|
@ -1764,14 +1754,6 @@ def test_git_quotes_no_space():
|
|||
def test_git_quotes_space():
|
||||
check_xonsh_ast({}, '$[git commit -am "wakka jawaka"]', False)
|
||||
|
||||
def test_git_two_quotes_space():
|
||||
check_xonsh({}, '$[git commit -am "wakka jawaka"]\n'
|
||||
'$[git commit -am "flock jawaka"]\n', False)
|
||||
|
||||
def test_git_two_quotes_space_space():
|
||||
check_xonsh({}, '$[git commit -am "wakka jawaka" ]\n'
|
||||
'$[git commit -am "flock jawaka milwaka" ]\n', False)
|
||||
|
||||
def test_ls_quotes_3_space():
|
||||
check_xonsh_ast({}, '$[ls "wakka jawaka baraka"]', False)
|
||||
|
||||
|
@ -1787,6 +1769,28 @@ def test_comment_only():
|
|||
def test_echo_slash_question():
|
||||
check_xonsh_ast({}, '![echo /?]', False)
|
||||
|
||||
def test_git_two_quotes_space():
|
||||
check_xonsh({}, '$[git commit -am "wakka jawaka"]\n'
|
||||
'$[git commit -am "flock jawaka"]\n', False)
|
||||
|
||||
def test_git_two_quotes_space_space():
|
||||
check_xonsh({}, '$[git commit -am "wakka jawaka" ]\n'
|
||||
'$[git commit -am "flock jawaka milwaka" ]\n', False)
|
||||
|
||||
def test_bang_ls_dot_nesting_var():
|
||||
check_xonsh({}, 'x = "."; !(ls @(None or x))', False)
|
||||
|
||||
def test_ls_dot_nesting_var():
|
||||
check_xonsh({}, 'x = "."; $(ls @(None or x))', False)
|
||||
|
||||
def test_bang_git_two_quotes_space():
|
||||
check_xonsh({}, '![git commit -am "wakka jawaka"]\n'
|
||||
'![git commit -am "flock jawaka"]\n', False)
|
||||
|
||||
def test_bang_git_two_quotes_space_space():
|
||||
check_xonsh({}, '![git commit -am "wakka jawaka" ]\n'
|
||||
'![git commit -am "flock jawaka milwaka" ]\n', False)
|
||||
|
||||
|
||||
_error_names = {'e', 'err', '2'}
|
||||
_output_names = {'', 'o', 'out', '1'}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Tests the xonsh lexer."""
|
||||
"""Tests xonsh tools."""
|
||||
import os
|
||||
import pathlib
|
||||
from tempfile import TemporaryDirectory
|
||||
import stat
|
||||
import builtins
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -15,7 +16,7 @@ from xonsh.tools import (
|
|||
bool_or_int_to_str, bool_to_str, check_for_partial_string,
|
||||
dynamic_cwd_tuple_to_str, ensure_int_or_slice, ensure_string,
|
||||
env_path_to_str, escape_windows_cmd_string, executables_in,
|
||||
expand_case_matching, find_next_break, is_bool, is_bool_or_int,
|
||||
expand_case_matching, find_next_break, iglobpath, is_bool, is_bool_or_int,
|
||||
is_callable, is_dynamic_cwd_width, is_env_path, is_float, is_int,
|
||||
is_int_as_str, is_logfile_opt, is_slice_as_str, is_string,
|
||||
is_string_or_callable, logfile_opt_to_str, str_to_env_path,
|
||||
|
@ -25,6 +26,8 @@ from xonsh.tools import (
|
|||
pathsep_to_upper_seq, seq_to_upper_pathsep,
|
||||
)
|
||||
from xonsh.commands_cache import CommandsCache
|
||||
from xonsh.built_ins import expand_path
|
||||
from xonsh.environ import Env
|
||||
|
||||
from tools import skip_if_on_windows
|
||||
|
||||
|
@ -307,6 +310,7 @@ def test_subproc_toks_pyeval_redirect():
|
|||
assert (exp == obs)
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
@pytest.mark.parametrize('inp, exp', [
|
||||
('f(x.', 'x.'),
|
||||
('f(1,x.', 'x.'),
|
||||
|
@ -475,7 +479,170 @@ def test_is_string_seq_false():
|
|||
|
||||
def test_is_nonstring_seq_of_strings_true():
|
||||
assert is_nonstring_seq_of_strings(['42.0'])
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
assert not is_nonstring_seq_of_strings([42.0])
|
||||
|
||||
|
||||
def test_pathsep_to_seq():
|
||||
cases = [
|
||||
('', []),
|
||||
('a', ['a']),
|
||||
(os.pathsep.join(['a', 'b']), ['a', 'b']),
|
||||
(os.pathsep.join(['a', 'b', 'c']), ['a', 'b', 'c']),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = pathsep_to_seq(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_seq_to_pathsep():
|
||||
cases = [
|
||||
([], ''),
|
||||
(['a'], 'a'),
|
||||
(['a', 'b'], os.pathsep.join(['a', 'b'])),
|
||||
(['a', 'b', 'c'], os.pathsep.join(['a', 'b', 'c'])),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = seq_to_pathsep(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_pathsep_to_upper_seq():
|
||||
cases = [
|
||||
('', []),
|
||||
('a', ['A']),
|
||||
(os.pathsep.join(['a', 'B']), ['A', 'B']),
|
||||
(os.pathsep.join(['A', 'b', 'c']), ['A', 'B', 'C']),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = pathsep_to_upper_seq(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_seq_to_upper_pathsep():
|
||||
cases = [
|
||||
([], ''),
|
||||
(['a'], 'A'),
|
||||
(['a', 'b'], os.pathsep.join(['A', 'B'])),
|
||||
(['a', 'B', 'c'], os.pathsep.join(['A', 'B', 'C'])),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = seq_to_upper_pathsep(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_is_env_path():
|
||||
cases = [
|
||||
('/home/wakka', False),
|
||||
(['/home/jawaka'], False),
|
||||
(EnvPath(['/home/jawaka']), True),
|
||||
(EnvPath(['jawaka']), True),
|
||||
(EnvPath(b'jawaka:wakka'), True),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = is_env_path(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_str_to_env_path():
|
||||
cases = [
|
||||
('/home/wakka', ['/home/wakka']),
|
||||
('/home/wakka' + os.pathsep + '/home/jawaka',
|
||||
['/home/wakka', '/home/jawaka']),
|
||||
(b'/home/wakka', ['/home/wakka']),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = str_to_env_path(inp)
|
||||
assert exp == obs.paths
|
||||
|
||||
|
||||
def test_env_path_to_str():
|
||||
cases = [
|
||||
(['/home/wakka'], '/home/wakka'),
|
||||
(['/home/wakka', '/home/jawaka'],
|
||||
'/home/wakka' + os.pathsep + '/home/jawaka'),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = env_path_to_str(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_env_path():
|
||||
def expand(path):
|
||||
return os.path.expanduser(os.path.expandvars(path))
|
||||
|
||||
getitem_cases = [
|
||||
('xonsh_dir', 'xonsh_dir'),
|
||||
('.', '.'),
|
||||
('../', '../'),
|
||||
('~/', '~/'),
|
||||
(b'~/../', '~/../'),
|
||||
]
|
||||
with mock_xonsh_env(TOOLS_ENV):
|
||||
for inp, exp in getitem_cases:
|
||||
obs = EnvPath(inp)[0] # call to __getitem__
|
||||
assert expand(exp) == obs
|
||||
|
||||
with mock_xonsh_env(ENCODE_ENV_ONLY):
|
||||
for inp, exp in getitem_cases:
|
||||
obs = EnvPath(inp)[0] # call to __getitem__
|
||||
assert exp == obs
|
||||
|
||||
# cases that involve path-separated strings
|
||||
multipath_cases = [
|
||||
(os.pathsep.join(['xonsh_dir', '../', '.', '~/']),
|
||||
['xonsh_dir', '../', '.', '~/']),
|
||||
('/home/wakka' + os.pathsep + '/home/jakka' + os.pathsep + '~/',
|
||||
['/home/wakka', '/home/jakka', '~/'])
|
||||
]
|
||||
with mock_xonsh_env(TOOLS_ENV):
|
||||
for inp, exp in multipath_cases:
|
||||
obs = [i for i in EnvPath(inp)]
|
||||
assert [expand(i) for i in exp] == obs
|
||||
|
||||
with mock_xonsh_env(ENCODE_ENV_ONLY):
|
||||
for inp, exp in multipath_cases:
|
||||
obs = [i for i in EnvPath(inp)]
|
||||
assert [i for i in exp] == obs
|
||||
|
||||
# cases that involve pathlib.Path objects
|
||||
pathlib_cases = [
|
||||
(pathlib.Path('/home/wakka'), ['/home/wakka'.replace('/', os.sep)]),
|
||||
(pathlib.Path('~/'), ['~']),
|
||||
(pathlib.Path('.'), ['.']),
|
||||
(['/home/wakka', pathlib.Path('/home/jakka'), '~/'],
|
||||
['/home/wakka', '/home/jakka'.replace('/', os.sep), '~/']),
|
||||
(['/home/wakka', pathlib.Path('../'), '../'],
|
||||
['/home/wakka', '..', '../']),
|
||||
(['/home/wakka', pathlib.Path('~/'), '~/'],
|
||||
['/home/wakka', '~', '~/']),
|
||||
]
|
||||
|
||||
with mock_xonsh_env(TOOLS_ENV):
|
||||
for inp, exp in pathlib_cases:
|
||||
# iterate over EnvPath to acquire all expanded paths
|
||||
obs = [i for i in EnvPath(inp)]
|
||||
assert [expand(i) for i in exp] == obs
|
||||
|
||||
def test_env_path_slices():
|
||||
# build os-dependent paths properly
|
||||
def mkpath(*paths):
|
||||
return os.sep + os.sep.join(paths)
|
||||
|
||||
# get all except the last element in a slice
|
||||
slice_last = [
|
||||
([mkpath('home', 'wakka'),
|
||||
mkpath('home', 'jakka'),
|
||||
mkpath('home', 'yakka')],
|
||||
[mkpath('home', 'wakka'),
|
||||
mkpath('home', 'jakka')])]
|
||||
|
||||
for inp, exp in slice_last:
|
||||
obs = EnvPath(inp)[:-1]
|
||||
assert exp == obs
|
||||
>>>>>>> master
|
||||
|
||||
@pytest.mark.parametrize('inp', ['42.0', [42.0]] )
|
||||
def test_is_nonstring_seq_of_strings_false(inp):
|
||||
|
@ -763,6 +930,7 @@ def test_bool_or_int_to_str(inp, exp):
|
|||
('(1:2:3)', slice(1, 2, 3)),
|
||||
('r', False),
|
||||
('r:11', False),
|
||||
<<<<<<< HEAD
|
||||
])
|
||||
def test_ensure_int_or_slice(inp, exp):
|
||||
obs = ensure_int_or_slice(inp)
|
||||
|
@ -802,11 +970,55 @@ def test_is_logfile_opt(inp, exp):
|
|||
|
||||
|
||||
@pytest.mark.parametrize('inp, exp', [
|
||||
=======
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = ensure_int_or_slice(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_is_dynamic_cwd_width():
|
||||
cases = [
|
||||
('20', False),
|
||||
('20%', False),
|
||||
((20, 'c'), False),
|
||||
((20.0, 'm'), False),
|
||||
((20.0, 'c'), True),
|
||||
((20.0, '%'), True),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = is_dynamic_cwd_width(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_is_logfile_opt():
|
||||
cases = [
|
||||
('throwback.log', True),
|
||||
('', True),
|
||||
(None, True),
|
||||
(True, False),
|
||||
(False, False),
|
||||
(42, False),
|
||||
([1, 2, 3], False),
|
||||
((1, 2), False),
|
||||
(("wrong", "parameter"), False)
|
||||
]
|
||||
if not ON_WINDOWS:
|
||||
cases.append(('/dev/null', True))
|
||||
for inp, exp in cases:
|
||||
obs = is_logfile_opt(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_to_logfile_opt():
|
||||
cases = [
|
||||
>>>>>>> master
|
||||
(True, None),
|
||||
(False, None),
|
||||
(1, None),
|
||||
(None, None),
|
||||
('throwback.log', 'throwback.log'),
|
||||
<<<<<<< HEAD
|
||||
skip_if_on_windows(('/dev/null', '/dev/null')),
|
||||
skip_if_on_windows(('/dev/nonexistent_dev', None))
|
||||
])
|
||||
|
@ -876,6 +1088,83 @@ def test_escape_windows_cmd_string(st, esc):
|
|||
def test_argvquote(st, esc):
|
||||
obs = argvquote(st)
|
||||
assert esc == obs
|
||||
=======
|
||||
]
|
||||
if not ON_WINDOWS:
|
||||
cases.append(('/dev/null', '/dev/null'))
|
||||
cases.append(('/dev/nonexistent_dev', None))
|
||||
for inp, exp in cases:
|
||||
obs = to_logfile_opt(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_logfile_opt_to_str():
|
||||
cases = [
|
||||
(None, ''),
|
||||
('', ''),
|
||||
('throwback.log', 'throwback.log'),
|
||||
('/dev/null', '/dev/null')
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = logfile_opt_to_str(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_to_dynamic_cwd_tuple():
|
||||
cases = [
|
||||
('20', (20.0, 'c')),
|
||||
('20%', (20.0, '%')),
|
||||
((20, 'c'), (20.0, 'c')),
|
||||
((20, '%'), (20.0, '%')),
|
||||
((20.0, 'c'), (20.0, 'c')),
|
||||
((20.0, '%'), (20.0, '%')),
|
||||
('inf', (float('inf'), 'c')),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = to_dynamic_cwd_tuple(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_dynamic_cwd_tuple_to_str():
|
||||
cases = [
|
||||
((20.0, 'c'), '20.0'),
|
||||
((20.0, '%'), '20.0%'),
|
||||
((float('inf'), 'c'), 'inf'),
|
||||
]
|
||||
for inp, exp in cases:
|
||||
obs = dynamic_cwd_tuple_to_str(inp)
|
||||
assert exp == obs
|
||||
|
||||
|
||||
def test_escape_windows_cmd_string():
|
||||
cases = [
|
||||
('', ''),
|
||||
('foo', 'foo'),
|
||||
('foo&bar', 'foo^&bar'),
|
||||
('foo$?-/_"\\', 'foo$?-/_^"\\'),
|
||||
('^&<>|', '^^^&^<^>^|'),
|
||||
('this /?', 'this /.')
|
||||
]
|
||||
for st, esc in cases:
|
||||
obs = escape_windows_cmd_string(st)
|
||||
assert esc == obs
|
||||
|
||||
|
||||
def test_argvquote():
|
||||
cases = [
|
||||
('', '""'),
|
||||
('foo', 'foo'),
|
||||
(r'arg1 "hallo, "world"" "\some\path with\spaces")',
|
||||
r'"arg1 \"hallo, \"world\"\" \"\some\path with\spaces\")"'),
|
||||
(r'"argument"2" argument3 argument4',
|
||||
r'"\"argument\"2\" argument3 argument4"'),
|
||||
(r'"\foo\bar bar\foo\" arg',
|
||||
r'"\"\foo\bar bar\foo\\\" arg"')
|
||||
]
|
||||
for st, esc in cases:
|
||||
obs = argvquote(st)
|
||||
assert esc == obs
|
||||
>>>>>>> master
|
||||
|
||||
|
||||
_leaders = ('', 'not empty')
|
||||
|
|
|
@ -13,7 +13,6 @@ import pytest
|
|||
|
||||
from xonsh.built_ins import ensure_list_of_strs
|
||||
from xonsh.environ import Env
|
||||
builtins.__xonsh_env__ = Env()
|
||||
from xonsh.base_shell import BaseShell
|
||||
from xonsh.execer import Execer
|
||||
from xonsh.tools import XonshBlockError
|
||||
|
@ -41,9 +40,11 @@ skip_if_on_darwin = pytest.mark.skipif(ON_DARWIN, reason='not Mac friendly')
|
|||
def sp(cmd):
|
||||
return subprocess.check_output(cmd, universal_newlines=True)
|
||||
|
||||
|
||||
class DummyStyler():
|
||||
styles = defaultdict(None.__class__)
|
||||
|
||||
|
||||
class DummyBaseShell(BaseShell):
|
||||
|
||||
def __init__(self):
|
||||
|
@ -70,28 +71,41 @@ class DummyShell:
|
|||
DEBUG_LEVEL = 0
|
||||
EXECER = None
|
||||
|
||||
|
||||
def execer_setup():
|
||||
# only setup one parser
|
||||
global EXECER
|
||||
if EXECER is None:
|
||||
EXECER = Execer(debug_level=DEBUG_LEVEL, login=False)
|
||||
|
||||
<<<<<<< HEAD
|
||||
def check_exec(input, xonsh_env, **kwargs):
|
||||
# with mock_xonsh_env(None):
|
||||
if not input.endswith('\n'):
|
||||
input += '\n'
|
||||
EXECER.debug_level = DEBUG_LEVEL
|
||||
EXECER.exec(input, **kwargs)
|
||||
=======
|
||||
|
||||
def check_exec(input, **kwargs):
|
||||
with mock_xonsh_env(None):
|
||||
if not input.endswith('\n'):
|
||||
input += '\n'
|
||||
EXECER.debug_level = DEBUG_LEVEL
|
||||
EXECER.exec(input, **kwargs)
|
||||
>>>>>>> master
|
||||
|
||||
|
||||
def check_eval(input):
|
||||
env = {'AUTO_CD': False, 'XONSH_ENCODING' :'utf-8',
|
||||
'XONSH_ENCODING_ERRORS': 'strict', 'PATH': []}
|
||||
env = Env({'AUTO_CD': False, 'XONSH_ENCODING': 'utf-8',
|
||||
'XONSH_ENCODING_ERRORS': 'strict', 'PATH': []})
|
||||
if ON_WINDOWS:
|
||||
env['PATHEXT'] = ['.COM', '.EXE', '.BAT', '.CMD']
|
||||
with mock_xonsh_env(env):
|
||||
EXECER.debug_level = DEBUG_LEVEL
|
||||
EXECER.eval(input)
|
||||
|
||||
|
||||
def check_parse(input):
|
||||
with mock_xonsh_env(None):
|
||||
EXECER.debug_level = DEBUG_LEVEL
|
||||
|
|
|
@ -36,7 +36,6 @@ from xonsh.tools import (
|
|||
from xonsh.commands_cache import CommandsCache
|
||||
|
||||
|
||||
ENV = None
|
||||
BUILTINS_LOADED = False
|
||||
INSPECTOR = LazyObject(Inspector, globals(), 'INSPECTOR')
|
||||
AT_EXIT_SIGNALS = (signal.SIGABRT, signal.SIGFPE, signal.SIGILL, signal.SIGSEGV,
|
||||
|
@ -86,8 +85,7 @@ def superhelper(x, name=''):
|
|||
|
||||
def expand_path(s):
|
||||
"""Takes a string path and expands ~ to home and environment vars."""
|
||||
global ENV
|
||||
if ENV.get('EXPAND_ENV_VARS'):
|
||||
if builtins.__xonsh_env__.get('EXPAND_ENV_VARS'):
|
||||
s = expandvars(s)
|
||||
return os.path.expanduser(s)
|
||||
|
||||
|
@ -138,7 +136,9 @@ def regexsearch(s):
|
|||
|
||||
def globsearch(s):
|
||||
csc = builtins.__xonsh_env__.get('CASE_SENSITIVE_COMPLETIONS')
|
||||
return globpath(s, ignore_case=(not csc), return_empty=True)
|
||||
glob_sorted = builtins.__xonsh_env__.get('GLOB_SORTED')
|
||||
return globpath(s, ignore_case=(not csc), return_empty=True,
|
||||
sort_result=glob_sorted)
|
||||
|
||||
|
||||
def pathsearch(func, s, pymode=False):
|
||||
|
@ -345,7 +345,7 @@ def run_subproc(cmds, captured=False):
|
|||
|
||||
Lastly, the captured argument affects only the last real command.
|
||||
"""
|
||||
global ENV
|
||||
env = builtins.__xonsh_env__
|
||||
background = False
|
||||
procinfo = {}
|
||||
if cmds[-1] == '&':
|
||||
|
@ -448,7 +448,7 @@ def run_subproc(cmds, captured=False):
|
|||
raise XonshError(e.format(cmd[0]))
|
||||
_stdin_file = None
|
||||
if (stdin is not None and
|
||||
ENV.get('XONSH_STORE_STDIN') and
|
||||
env.get('XONSH_STORE_STDIN') and
|
||||
captured == 'object' and
|
||||
__xonsh_commands_cache__.lazy_locate_binary('cat') and
|
||||
__xonsh_commands_cache__.lazy_locate_binary('tee')):
|
||||
|
@ -478,7 +478,7 @@ def run_subproc(cmds, captured=False):
|
|||
prev_is_proxy = False
|
||||
usetee = ((stdout is None) and
|
||||
(not background) and
|
||||
ENV.get('XONSH_STORE_STDOUT', False))
|
||||
env.get('XONSH_STORE_STDOUT', False))
|
||||
cls = TeePTYProc if usetee else Popen
|
||||
subproc_kwargs = {}
|
||||
if ON_POSIX and cls is Popen:
|
||||
|
@ -489,15 +489,15 @@ def run_subproc(cmds, captured=False):
|
|||
os.setpgid(0, _pipeline_group)
|
||||
signal.signal(signal.SIGTSTP, lambda n, f: signal.pause())
|
||||
subproc_kwargs['preexec_fn'] = _subproc_pre
|
||||
env = ENV.detype()
|
||||
denv = env.detype()
|
||||
if ON_WINDOWS:
|
||||
# Over write prompt variable as xonsh's $PROMPT does
|
||||
# not make much sense for other subprocs
|
||||
env['PROMPT'] = '$P$G'
|
||||
denv['PROMPT'] = '$P$G'
|
||||
try:
|
||||
proc = cls(aliased_cmd,
|
||||
universal_newlines=uninew,
|
||||
env=env,
|
||||
env=denv,
|
||||
stdin=stdin,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
|
@ -508,9 +508,9 @@ def run_subproc(cmds, captured=False):
|
|||
except FileNotFoundError:
|
||||
cmd = aliased_cmd[0]
|
||||
e = 'xonsh: subprocess mode: command not found: {0}'.format(cmd)
|
||||
sug = suggest_commands(cmd, ENV, builtins.aliases)
|
||||
sug = suggest_commands(cmd, env, builtins.aliases)
|
||||
if len(sug.strip()) > 0:
|
||||
e += '\n' + suggest_commands(cmd, ENV, builtins.aliases)
|
||||
e += '\n' + suggest_commands(cmd, env, builtins.aliases)
|
||||
raise XonshError(e)
|
||||
procs.append(proc)
|
||||
prev_proc = proc
|
||||
|
@ -523,8 +523,8 @@ def run_subproc(cmds, captured=False):
|
|||
'obj': prev_proc,
|
||||
'bg': background
|
||||
})
|
||||
if (ENV.get('XONSH_INTERACTIVE') and
|
||||
not ENV.get('XONSH_STORE_STDOUT') and
|
||||
if (env.get('XONSH_INTERACTIVE') and
|
||||
not env.get('XONSH_STORE_STDOUT') and
|
||||
not _capture_streams):
|
||||
# set title here to get current command running
|
||||
try:
|
||||
|
@ -559,8 +559,8 @@ def run_subproc(cmds, captured=False):
|
|||
if _capture_streams:
|
||||
# to get proper encoding from Popen, we have to
|
||||
# use a byte stream and then implement universal_newlines here
|
||||
output = output.decode(encoding=ENV.get('XONSH_ENCODING'),
|
||||
errors=ENV.get('XONSH_ENCODING_ERRORS'))
|
||||
output = output.decode(encoding=env.get('XONSH_ENCODING'),
|
||||
errors=env.get('XONSH_ENCODING_ERRORS'))
|
||||
output = output.replace('\r\n', '\n')
|
||||
else:
|
||||
hist.last_cmd_out = output
|
||||
|
@ -578,8 +578,8 @@ def run_subproc(cmds, captured=False):
|
|||
elif unnamed:
|
||||
errout = prev_proc.stderr.read()
|
||||
if named or unnamed:
|
||||
errout = errout.decode(encoding=ENV.get('XONSH_ENCODING'),
|
||||
errors=ENV.get('XONSH_ENCODING_ERRORS'))
|
||||
errout = errout.decode(encoding=env.get('XONSH_ENCODING'),
|
||||
errors=env.get('XONSH_ENCODING_ERRORS'))
|
||||
errout = errout.replace('\r\n', '\n')
|
||||
procinfo['stderr'] = errout
|
||||
|
||||
|
@ -593,7 +593,7 @@ def run_subproc(cmds, captured=False):
|
|||
if (not prev_is_proxy and
|
||||
hist.last_cmd_rtn is not None and
|
||||
hist.last_cmd_rtn > 0 and
|
||||
ENV.get('RAISE_SUBPROC_ERROR')):
|
||||
env.get('RAISE_SUBPROC_ERROR')):
|
||||
raise CalledProcessError(hist.last_cmd_rtn, aliased_cmd, output=output)
|
||||
if captured == 'stdout':
|
||||
return output
|
||||
|
@ -675,10 +675,10 @@ def load_builtins(execer=None, config=None, login=False, ctx=None):
|
|||
"""Loads the xonsh builtins into the Python builtins. Sets the
|
||||
BUILTINS_LOADED variable to True.
|
||||
"""
|
||||
global BUILTINS_LOADED, ENV
|
||||
global BUILTINS_LOADED
|
||||
# private built-ins
|
||||
builtins.__xonsh_config__ = {}
|
||||
builtins.__xonsh_env__ = ENV = Env(default_env(config=config, login=login))
|
||||
builtins.__xonsh_env__ = env = Env(default_env(config=config, login=login))
|
||||
builtins.__xonsh_help__ = helper
|
||||
builtins.__xonsh_superhelp__ = superhelper
|
||||
builtins.__xonsh_pathsearch__ = pathsearch
|
||||
|
@ -720,7 +720,7 @@ def load_builtins(execer=None, config=None, login=False, ctx=None):
|
|||
builtins.aliases.update(load_foreign_aliases(issue_warning=False))
|
||||
# history needs to be started after env and aliases
|
||||
# would be nice to actually include non-detyped versions.
|
||||
builtins.__xonsh_history__ = History(env=ENV.detype(),
|
||||
builtins.__xonsh_history__ = History(env=env.detype(),
|
||||
ts=[time.time(), None], locked=True)
|
||||
atexit.register(_lastflush)
|
||||
for sig in AT_EXIT_SIGNALS:
|
||||
|
@ -737,10 +737,10 @@ def unload_builtins():
|
|||
"""Removes the xonsh builtins from the Python builtins, if the
|
||||
BUILTINS_LOADED is True, sets BUILTINS_LOADED to False, and returns.
|
||||
"""
|
||||
global BUILTINS_LOADED, ENV
|
||||
if ENV is not None:
|
||||
ENV.undo_replace_env()
|
||||
ENV = None
|
||||
global BUILTINS_LOADED
|
||||
env = getattr(builtins, '__xonsh_env__', None)
|
||||
if isinstance(env, Env):
|
||||
env.undo_replace_env()
|
||||
if hasattr(builtins, '__xonsh_pyexit__'):
|
||||
builtins.exit = builtins.__xonsh_pyexit__
|
||||
if hasattr(builtins, '__xonsh_pyquit__'):
|
||||
|
|
|
@ -105,9 +105,11 @@ def _add_cdpaths(paths, prefix):
|
|||
"""Completes current prefix using CDPATH"""
|
||||
env = builtins.__xonsh_env__
|
||||
csc = env.get('CASE_SENSITIVE_COMPLETIONS')
|
||||
glob_sorted = env.get('GLOB_SORTED')
|
||||
for cdp in env.get('CDPATH'):
|
||||
test_glob = os.path.join(cdp, prefix) + '*'
|
||||
for s in iglobpath(test_glob, ignore_case=(not csc)):
|
||||
for s in iglobpath(test_glob, ignore_case=(not csc),
|
||||
sort_result=glob_sorted):
|
||||
if os.path.isdir(s):
|
||||
paths.add(os.path.basename(s))
|
||||
|
||||
|
@ -222,9 +224,10 @@ def _subsequence_match_iter(ref, typed):
|
|||
|
||||
def _expand_one(sofar, nextone, csc):
|
||||
out = set()
|
||||
glob_sorted = builtins.__xonsh_env__.get('GLOB_SORTED')
|
||||
for i in sofar:
|
||||
_glob = os.path.join(_joinpath(i), '*') if i is not None else '*'
|
||||
for j in iglobpath(_glob):
|
||||
for j in iglobpath(_glob, sort_result=glob_sorted):
|
||||
j = os.path.basename(j)
|
||||
if subsequence_match(j, nextone, csc):
|
||||
out.add((i or ()) + (j, ))
|
||||
|
@ -247,7 +250,9 @@ def complete_path(prefix, line, start, end, ctx, cdpath=True, filtfunc=None):
|
|||
paths = set()
|
||||
env = builtins.__xonsh_env__
|
||||
csc = env.get('CASE_SENSITIVE_COMPLETIONS')
|
||||
for s in iglobpath(prefix + '*', ignore_case=(not csc)):
|
||||
glob_sorted = env.get('GLOB_SORTED')
|
||||
for s in iglobpath(prefix + '*', ignore_case=(not csc),
|
||||
sort_result=glob_sorted):
|
||||
paths.add(s)
|
||||
if len(paths) == 0 and env.get('SUBSEQUENCE_PATH_COMPLETION'):
|
||||
# this block implements 'subsequence' matching, similar to fish and zsh.
|
||||
|
@ -267,7 +272,8 @@ def complete_path(prefix, line, start, end, ctx, cdpath=True, filtfunc=None):
|
|||
paths |= {_joinpath(i) for i in matches_so_far}
|
||||
if len(paths) == 0 and env.get('FUZZY_PATH_COMPLETION'):
|
||||
threshold = env.get('SUGGEST_THRESHOLD')
|
||||
for s in iglobpath(os.path.dirname(prefix) + '*', ignore_case=(not csc)):
|
||||
for s in iglobpath(os.path.dirname(prefix) + '*', ignore_case=(not csc),
|
||||
sort_result=glob_sorted):
|
||||
if levenshtein(prefix, s, threshold) < threshold:
|
||||
paths.add(s)
|
||||
if tilde in prefix:
|
||||
|
|
|
@ -100,6 +100,7 @@ DEFAULT_ENSURERS = {
|
|||
dynamic_cwd_tuple_to_str),
|
||||
'FORCE_POSIX_PATHS': (is_bool, to_bool, bool_to_str),
|
||||
'FUZZY_PATH_COMPLETION': (is_bool, to_bool, bool_to_str),
|
||||
'GLOB_SORTED': (is_bool, to_bool, bool_to_str),
|
||||
'HISTCONTROL': (is_string_set, csv_to_set, set_to_csv),
|
||||
'IGNOREEOF': (is_bool, to_bool, bool_to_str),
|
||||
'INTENSIFY_COLORS_ON_WIN':(always_false, intensify_colors_on_win_setter,
|
||||
|
@ -222,6 +223,7 @@ DEFAULT_VALUES = {
|
|||
'EXPAND_ENV_VARS': True,
|
||||
'FORCE_POSIX_PATHS': False,
|
||||
'FUZZY_PATH_COMPLETION': True,
|
||||
'GLOB_SORTED': True,
|
||||
'HISTCONTROL': set(),
|
||||
'IGNOREEOF': False,
|
||||
'INDENT': ' ',
|
||||
|
@ -379,6 +381,9 @@ DEFAULT_DOCS = {
|
|||
"used as a fallback if no other completions succeed but can be used "
|
||||
"as a way to adjust for typographical errors. If ``True``, then, e.g.,"
|
||||
" ``xonhs`` will match ``xonsh``."),
|
||||
'GLOB_SORTED': VarDocs(
|
||||
"Toggles whether globbing results are manually sorted. If ``False``, "
|
||||
"the results are returned in arbitrary order."),
|
||||
'HISTCONTROL': VarDocs(
|
||||
'A set of strings (comma-separated list in string form) of options '
|
||||
'that determine what commands are saved to the history list. By '
|
||||
|
|
|
@ -19,7 +19,7 @@ class LazyObject(object):
|
|||
load : function with no arguments
|
||||
A loader function that performs the actual object construction.
|
||||
ctx : Mapping
|
||||
Context to replace the LazyAndSelfDestructiveObject instance in
|
||||
Context to replace the LazyObject instance in
|
||||
with the object returned by load().
|
||||
name : str
|
||||
Name in the context to give the loaded object. This *should*
|
||||
|
@ -56,6 +56,10 @@ class LazyObject(object):
|
|||
obj = self._lazy_obj()
|
||||
yield from obj
|
||||
|
||||
def __getitem__(self, item):
|
||||
obj = self._lazy_obj()
|
||||
return obj[item]
|
||||
|
||||
|
||||
class LazyDict(abc.MutableMapping):
|
||||
|
||||
|
@ -81,7 +85,7 @@ class LazyDict(abc.MutableMapping):
|
|||
A mapping of loader function that performs the actual value
|
||||
construction upon acces.
|
||||
ctx : Mapping
|
||||
Context to replace the LazyAndSelfDestructiveDict instance in
|
||||
Context to replace the LazyDict instance in
|
||||
with the the fully loaded mapping.
|
||||
name : str
|
||||
Name in the context to give the loaded mapping. This *should*
|
||||
|
@ -145,7 +149,7 @@ class LazyBool(object):
|
|||
load : function with no arguments
|
||||
A loader function that performs the actual boolean evaluation.
|
||||
ctx : Mapping
|
||||
Context to replace the LazyAndSelfDestructiveDict instance in
|
||||
Context to replace the LazyBool instance in
|
||||
with the the fully loaded mapping.
|
||||
name : str
|
||||
Name in the context to give the loaded mapping. This *should*
|
||||
|
|
130
xonsh/tools.py
130
xonsh/tools.py
|
@ -38,10 +38,8 @@ from subprocess import CalledProcessError
|
|||
# adding further imports from xonsh modules is discouraged to avoid circular
|
||||
# dependencies
|
||||
from xonsh.lazyasd import LazyObject, LazyDict
|
||||
from xonsh.platform import (
|
||||
has_prompt_toolkit, scandir,
|
||||
DEFAULT_ENCODING, ON_LINUX, ON_WINDOWS, PYTHON_VERSION_INFO,
|
||||
)
|
||||
from xonsh.platform import (has_prompt_toolkit, scandir, DEFAULT_ENCODING,
|
||||
ON_LINUX, ON_WINDOWS, PYTHON_VERSION_INFO)
|
||||
|
||||
|
||||
@functools.lru_cache(1)
|
||||
|
@ -145,8 +143,8 @@ class EnvPath(collections.MutableSequence):
|
|||
# in order to be able to retrieve it later, for cases such as
|
||||
# when a generator expression was passed as an argument
|
||||
args = list(args)
|
||||
if not all(isinstance(i, (str, bytes, pathlib.Path)) \
|
||||
for i in args):
|
||||
if not all(isinstance(i, (str, bytes, pathlib.Path))
|
||||
for i in args):
|
||||
# make TypeError's message as informative as possible
|
||||
# when given an invalid initialization sequence
|
||||
raise TypeError(
|
||||
|
@ -222,7 +220,8 @@ def _is_not_lparen_and_rparen(lparens, rtok):
|
|||
|
||||
def find_next_break(line, mincol=0, lexer=None):
|
||||
"""Returns the column number of the next logical break in subproc mode.
|
||||
This function may be useful in finding the maxcol argument of subproc_toks().
|
||||
This function may be useful in finding the maxcol argument of
|
||||
subproc_toks().
|
||||
"""
|
||||
if mincol >= 1:
|
||||
line = line[mincol:]
|
||||
|
@ -409,13 +408,15 @@ def get_sep():
|
|||
""" Returns the appropriate filepath separator char depending on OS and
|
||||
xonsh options set
|
||||
"""
|
||||
return (os.altsep if ON_WINDOWS
|
||||
and builtins.__xonsh_env__.get('FORCE_POSIX_PATHS') else
|
||||
os.sep)
|
||||
if ON_WINDOWS and builtins.__xonsh_env__.get('FORCE_POSIX_PATHS'):
|
||||
return os.altsep
|
||||
else:
|
||||
return os.sep
|
||||
|
||||
|
||||
def fallback(cond, backup):
|
||||
"""Decorator for returning the object if cond is true and a backup if cond is false.
|
||||
"""Decorator for returning the object if cond is true and a backup if cond
|
||||
is false.
|
||||
"""
|
||||
def dec(obj):
|
||||
return obj if cond else backup
|
||||
|
@ -481,11 +482,14 @@ def _yield_accessible_unix_file_names(path):
|
|||
|
||||
|
||||
def _executables_in_posix(path):
|
||||
if PYTHON_VERSION_INFO < (3, 5, 0):
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
elif PYTHON_VERSION_INFO < (3, 5, 0):
|
||||
for fname in os.listdir(path):
|
||||
fpath = os.path.join(path, fname)
|
||||
if (os.path.exists(fpath) and os.access(fpath, os.X_OK) and \
|
||||
(not os.path.isdir(fpath))):
|
||||
fpath = os.path.join(path, fname)
|
||||
if (os.path.exists(fpath) and
|
||||
os.access(fpath, os.X_OK) and
|
||||
(not os.path.isdir(fpath))):
|
||||
yield fname
|
||||
else:
|
||||
yield from _yield_accessible_unix_file_names(path)
|
||||
|
@ -559,9 +563,10 @@ def suggest_commands(cmd, env, aliases):
|
|||
|
||||
for path in filter(os.path.isdir, env.get('PATH')):
|
||||
for _file in executables_in(path):
|
||||
if _file not in suggested \
|
||||
and levenshtein(_file.lower(), cmd, thresh) < thresh:
|
||||
suggested[_file] = 'Command ({0})'.format(os.path.join(path, _file))
|
||||
if (_file not in suggested and
|
||||
levenshtein(_file.lower(), cmd, thresh) < thresh):
|
||||
suggested[_file] = \
|
||||
'Command ({0})'.format(os.path.join(path, _file))
|
||||
|
||||
suggested = collections.OrderedDict(
|
||||
sorted(suggested.items(),
|
||||
|
@ -656,6 +661,7 @@ def is_writable_file(filepath):
|
|||
# and ensure that directory is writable instead
|
||||
return os.access(os.path.dirname(filepath), os.W_OK)
|
||||
|
||||
|
||||
# Modified from Public Domain code, by Magnus Lie Hetland
|
||||
# from http://hetland.org/coding/python/levenshtein.py
|
||||
def levenshtein(a, b, max_dist=float('inf')):
|
||||
|
@ -755,6 +761,7 @@ def is_int(x):
|
|||
"""Tests if something is an integer"""
|
||||
return isinstance(x, int)
|
||||
|
||||
|
||||
def is_int_as_str(x):
|
||||
"""
|
||||
Tests if something is an integer
|
||||
|
@ -778,10 +785,12 @@ def is_string(x):
|
|||
"""Tests if something is a string"""
|
||||
return isinstance(x, str)
|
||||
|
||||
|
||||
def is_slice(x):
|
||||
"""Tests if something is a slice"""
|
||||
return isinstance(x, slice)
|
||||
|
||||
|
||||
def is_slice_as_str(x):
|
||||
"""
|
||||
Tests if a str is a slice
|
||||
|
@ -800,6 +809,7 @@ def is_slice_as_str(x):
|
|||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_callable(x):
|
||||
"""Tests if something is callable"""
|
||||
return callable(x)
|
||||
|
@ -839,7 +849,9 @@ def str_to_env_path(x):
|
|||
|
||||
|
||||
def env_path_to_str(x):
|
||||
"""Converts an environment path to a string by joining on the OS separator."""
|
||||
"""Converts an environment path to a string by joining on the OS
|
||||
separator.
|
||||
"""
|
||||
return os.pathsep.join(x)
|
||||
|
||||
|
||||
|
@ -855,8 +867,10 @@ def is_logfile_opt(x):
|
|||
"""
|
||||
if x is None:
|
||||
return True
|
||||
return False if not isinstance(x, str) else \
|
||||
(is_writable_file(x) or x == '')
|
||||
if not isinstance(x, str):
|
||||
return False
|
||||
else:
|
||||
return (is_writable_file(x) or x == '')
|
||||
|
||||
|
||||
def to_logfile_opt(x):
|
||||
|
@ -903,7 +917,9 @@ def to_bool(x):
|
|||
|
||||
|
||||
def bool_to_str(x):
|
||||
"""Converts a bool to an empty string if False and the string '1' if True."""
|
||||
"""Converts a bool to an empty string if False and the string '1' if
|
||||
True.
|
||||
"""
|
||||
return '1' if x else ''
|
||||
|
||||
|
||||
|
@ -1148,12 +1164,14 @@ HISTORY_UNITS = LazyObject(lambda: {
|
|||
}, globals(), 'HISTORY_UNITS')
|
||||
"""Maps lowercase unit names to canonical name and conversion utilities."""
|
||||
|
||||
|
||||
def is_history_tuple(x):
|
||||
"""Tests if something is a proper history value, units tuple."""
|
||||
if isinstance(x, abc.Sequence) and len(x) == 2 and \
|
||||
isinstance(x[0], (int, float)) and \
|
||||
x[1].lower() in CANON_HISTORY_UNITS:
|
||||
return True
|
||||
if (isinstance(x, abc.Sequence) and
|
||||
len(x) == 2 and
|
||||
isinstance(x[0], (int, float)) and
|
||||
x[1].lower() in CANON_HISTORY_UNITS):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
@ -1161,8 +1179,10 @@ def is_dynamic_cwd_width(x):
|
|||
""" Determine if the input is a valid input for the DYNAMIC_CWD_WIDTH
|
||||
environement variable.
|
||||
"""
|
||||
return isinstance(x, tuple) and len(x) == 2 and isinstance(x[0], float) and \
|
||||
(x[1] in set('c%'))
|
||||
return (isinstance(x, tuple) and
|
||||
len(x) == 2 and
|
||||
isinstance(x[0], float) and
|
||||
x[1] in set('c%'))
|
||||
|
||||
|
||||
def to_dynamic_cwd_tuple(x):
|
||||
|
@ -1191,6 +1211,7 @@ RE_HISTORY_TUPLE = LazyObject(
|
|||
lambda: re.compile('([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\s*([A-Za-z]*)'),
|
||||
globals(), 'RE_HISTORY_TUPLE')
|
||||
|
||||
|
||||
def to_history_tuple(x):
|
||||
"""Converts to a canonincal history tuple."""
|
||||
if not isinstance(x, (abc.Sequence, float, int)):
|
||||
|
@ -1321,7 +1342,7 @@ _STRINGS = (_RE_STRING_TRIPLE_DOUBLE,
|
|||
_RE_STRING_DOUBLE,
|
||||
_RE_STRING_SINGLE)
|
||||
RE_BEGIN_STRING = LazyObject(
|
||||
lambda: re.compile("(" + _RE_STRING_START + \
|
||||
lambda: re.compile("(" + _RE_STRING_START +
|
||||
'(' + "|".join(_STRINGS) + '))'),
|
||||
globals(), 'RE_BEGIN_STRING')
|
||||
"""Regular expression matching the start of a string, including quotes and
|
||||
|
@ -1414,13 +1435,14 @@ def check_for_partial_string(x):
|
|||
# source code (root/Lib/ntpath.py, line 353)
|
||||
|
||||
def _is_in_env(name):
|
||||
ENV = builtins.__xonsh_env__
|
||||
return name in ENV._d or name in ENV._defaults
|
||||
env = builtins.__xonsh_env__
|
||||
return name in env._d or name in env._defaults
|
||||
|
||||
|
||||
def _get_env_string(name):
|
||||
ENV = builtins.__xonsh_env__
|
||||
value = ENV.get(name)
|
||||
ensurer = ENV.get_ensurer(name)
|
||||
env = builtins.__xonsh_env__
|
||||
value = env.get(name)
|
||||
ensurer = env.get_ensurer(name)
|
||||
if ensurer.detype is bool_to_str:
|
||||
value = ensure_string(value)
|
||||
else:
|
||||
|
@ -1430,12 +1452,12 @@ def _get_env_string(name):
|
|||
|
||||
def expandvars(path):
|
||||
"""Expand shell variables of the forms $var, ${var} and %var%.
|
||||
|
||||
Unknown variables are left unchanged."""
|
||||
ENV = builtins.__xonsh_env__
|
||||
Unknown variables are left unchanged.
|
||||
"""
|
||||
env = builtins.__xonsh_env__
|
||||
if isinstance(path, bytes):
|
||||
path = path.decode(encoding=ENV.get('XONSH_ENCODING'),
|
||||
errors=ENV.get('XONSH_ENCODING_ERRORS'))
|
||||
path = path.decode(encoding=env.get('XONSH_ENCODING'),
|
||||
errors=env.get('XONSH_ENCODING_ERRORS'))
|
||||
elif isinstance(path, pathlib.Path):
|
||||
# get the path's string representation
|
||||
path = str(path)
|
||||
|
@ -1529,6 +1551,7 @@ def expandvars(path):
|
|||
# File handling tools
|
||||
#
|
||||
|
||||
|
||||
def backup_file(fname):
|
||||
"""Moves an existing file to a new name that has the current time right
|
||||
before the extension.
|
||||
|
@ -1593,26 +1616,41 @@ def expand_case_matching(s):
|
|||
return ''.join(t)
|
||||
|
||||
|
||||
def globpath(s, ignore_case=False, return_empty=False):
|
||||
def globpath(s, ignore_case=False, return_empty=False, sort_result=None):
|
||||
"""Simple wrapper around glob that also expands home and env vars."""
|
||||
o, s = _iglobpath(s, ignore_case=ignore_case)
|
||||
o, s = _iglobpath(s, ignore_case=ignore_case, sort_result=sort_result)
|
||||
o = list(o)
|
||||
no_match = [] if return_empty else [s]
|
||||
return o if len(o) != 0 else no_match
|
||||
|
||||
|
||||
def _iglobpath(s, ignore_case=False):
|
||||
def _iglobpath(s, ignore_case=False, sort_result=None):
|
||||
s = builtins.__xonsh_expand_path__(s)
|
||||
if sort_result is None:
|
||||
sort_result = builtins.__xonsh_env__.get('GLOB_SORTED')
|
||||
if ignore_case:
|
||||
s = expand_case_matching(s)
|
||||
if sys.version_info > (3, 5):
|
||||
if '**' in s and '**/*' not in s:
|
||||
s = s.replace('**', '**/*')
|
||||
# `recursive` is only a 3.5+ kwarg.
|
||||
return glob.iglob(s, recursive=True), s
|
||||
if sort_result:
|
||||
paths = glob.glob(s, recursive=True)
|
||||
paths.sort()
|
||||
paths = iter(paths)
|
||||
else:
|
||||
paths = glob.iglob(s, recursive=True)
|
||||
return paths, s
|
||||
else:
|
||||
return glob.iglob(s), s
|
||||
if sort_result:
|
||||
paths = glob.glob(s)
|
||||
paths.sort()
|
||||
paths = iter(paths)
|
||||
else:
|
||||
paths = glob.iglob(s)
|
||||
return paths, s
|
||||
|
||||
def iglobpath(s, ignore_case=False):
|
||||
|
||||
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)[0]
|
||||
return _iglobpath(s, ignore_case=ignore_case, sort_result=sort_result)[0]
|
||||
|
|
|
@ -44,6 +44,17 @@
|
|||
"package": "xonsh-pacman-tabcomplete",
|
||||
"url": "https://github.com/gforsyth/xonsh-pacman-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to pacman inside of xonsh."]
|
||||
},
|
||||
{"name": "scrapy_tabcomplete",
|
||||
"package": "xonsh-scrapy-tabcomplete",
|
||||
"url": "https://github.com/Granitas/xonsh-scrapy-tabcomplete",
|
||||
"description": ["Adds tabcomplete functionality to scrapy inside of xonsh."]
|
||||
},
|
||||
{"name": "autoxsh",
|
||||
"package": "xonsh-autoxsh",
|
||||
"url": "https://github.com/Granitas/xonsh-autoxsh",
|
||||
"description": ["Adds automatic execution of xonsh script files called",
|
||||
"`.autoxsh` when enterting a directory with `cd` function"]
|
||||
}
|
||||
],
|
||||
"packages": {
|
||||
|
@ -83,6 +94,20 @@
|
|||
"install": {
|
||||
"pip": "pip install xonsh-pacman-tabcomplete"
|
||||
}
|
||||
},
|
||||
"xonsh-scrapy-tabcomplete": {
|
||||
"license": "GPLv3",
|
||||
"url": "https://github.com/Granitas/xonsh-scrapy-tabcomplete",
|
||||
"install": {
|
||||
"pip": "pip install xonsh-scrapy-tabcomplete"
|
||||
}
|
||||
},
|
||||
"xonsh-autoxsh": {
|
||||
"license": "GPLv3",
|
||||
"url": "https://github.com/Granitas/xonsh-autoxsh",
|
||||
"install": {
|
||||
"pip": "pip install xonsh-autoxsh"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue