mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
more
This commit is contained in:
parent
834e45f3ae
commit
f056fe01c3
4 changed files with 50 additions and 21 deletions
|
@ -1792,6 +1792,9 @@ def test_comment_only():
|
|||
def test_echo_slash_question():
|
||||
check_xonsh_ast({}, '![echo /?]', False)
|
||||
|
||||
def test_bad_quotes():
|
||||
with pytest.raises(SyntaxError):
|
||||
check_xonsh_ast({}, '![echo """hello]', False)
|
||||
|
||||
def test_redirect():
|
||||
assert check_xonsh_ast({}, '$[cat < input.txt]', False)
|
||||
|
|
|
@ -24,7 +24,7 @@ from xonsh.tools import (
|
|||
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,
|
||||
ensure_timestamp, get_portions, is_balanced, subexpr_before_unbalanced,
|
||||
swap_values, get_logical_line, replace_logical_line
|
||||
swap_values, get_logical_line, replace_logical_line, check_quotes,
|
||||
)
|
||||
from xonsh.environ import Env
|
||||
|
||||
|
@ -208,6 +208,11 @@ def test_subproc_toks_hello_mom_second():
|
|||
assert exp == obs
|
||||
|
||||
|
||||
def test_subproc_toks_hello_bad_quotes():
|
||||
with pytest.raises(SyntaxError):
|
||||
obs = subproc_toks('echo """hello', lexer=LEXER, returnline=True)
|
||||
|
||||
|
||||
def test_subproc_toks_comment():
|
||||
exp = None
|
||||
obs = subproc_toks('# I am a comment', lexer=LEXER, returnline=True)
|
||||
|
@ -353,6 +358,17 @@ def test_replace_logical_line(src, idx, exp_line, exp_n):
|
|||
assert exp == obs
|
||||
|
||||
|
||||
@pytest.mark.parametrize('inp, exp', [
|
||||
('f(1,10),x.y', True),
|
||||
('"x"', True),
|
||||
("'y'", True),
|
||||
('b"x"', True),
|
||||
("r'y'", True),
|
||||
])
|
||||
def test_check_quotes(inp, exp):
|
||||
obs = check_quotes(inp)
|
||||
assert exp is obs
|
||||
|
||||
@pytest.mark.parametrize('inp', [
|
||||
'f(1,10),x.y',
|
||||
])
|
||||
|
|
|
@ -19,6 +19,7 @@ from xonsh.platform import PYTHON_VERSION_INFO
|
|||
from xonsh.tokenize import SearchPath, StringPrefix
|
||||
from xonsh.lazyasd import LazyObject
|
||||
from xonsh.parsers.context_check import check_contexts
|
||||
from xonsh.tools import check_quotes
|
||||
|
||||
RE_SEARCHPATH = LazyObject(lambda: re.compile(SearchPath), globals(),
|
||||
'RE_SEARCHPATH')
|
||||
|
@ -2505,25 +2506,7 @@ class BaseParser(object):
|
|||
"""
|
||||
if not isinstance(p, ast.Str):
|
||||
return p
|
||||
s = p.s
|
||||
if s.startswith('"""'):
|
||||
ok = s.endswith('"""')
|
||||
elif s.endswith('"""'):
|
||||
ok = s.startswith('"""')
|
||||
elif s.startswith("'''"):
|
||||
ok = s.endswith("'''")
|
||||
elif s.endswith("'''"):
|
||||
ok = s.startswith("'''")
|
||||
elif s.startswith('"'):
|
||||
ok = s.endswith('"')
|
||||
elif s.endswith('"'):
|
||||
ok = s.startswith('"')
|
||||
elif s.startswith("'"):
|
||||
ok = s.endswith("'")
|
||||
elif s.endswith("'"):
|
||||
ok = s.startswith("'")
|
||||
else:
|
||||
ok = True
|
||||
ok = check_quotes(p.s)
|
||||
if not ok:
|
||||
msg = ("Subprocess tokes must have matching begining and ending "
|
||||
"quotes, if they start or end with quotes, got {0}")
|
||||
|
|
|
@ -319,6 +319,8 @@ def subproc_toks(line, mincol=-1, maxcol=None, lexer=None, returnline=False):
|
|||
else:
|
||||
tok.lexpos = len(line)
|
||||
break
|
||||
elif isinstance(tok.value, str) and not check_quotes(tok.value):
|
||||
return
|
||||
else:
|
||||
if len(toks) > 0 and toks[-1].type in END_TOK_TYPES:
|
||||
if _is_not_lparen_and_rparen(lparens, toks[-1]):
|
||||
|
@ -346,6 +348,24 @@ def subproc_toks(line, mincol=-1, maxcol=None, lexer=None, returnline=False):
|
|||
return rtn
|
||||
|
||||
|
||||
def check_quotes(s):
|
||||
"""Checks a string to make sure that if it starts with quotes, it also
|
||||
ends with quotes.
|
||||
"""
|
||||
starts_as_str = RE_BEGIN_STRING.match(s) is not None
|
||||
ends_as_str = s.endswith('"') or s.endswith("'")
|
||||
if not starts_as_str and not ends_as_str:
|
||||
ok = True
|
||||
elif starts_as_str and not ends_as_str:
|
||||
ok = False
|
||||
elif not starts_as_str and ends_as_str:
|
||||
ok = False
|
||||
else:
|
||||
m = RE_COMPLETE_STRING.match(s)
|
||||
ok = m is not None
|
||||
return ok
|
||||
|
||||
|
||||
def get_logical_line(lines, idx):
|
||||
"""Returns a single logical line (i.e. one without line continuations)
|
||||
from a list of lines. This line should begin at index idx. This also
|
||||
|
@ -1526,7 +1546,7 @@ def format_std_prepost(template, env=None):
|
|||
return s
|
||||
|
||||
|
||||
_RE_STRING_START = "[bBrRuU]*"
|
||||
_RE_STRING_START = "[bBprRuU]*"
|
||||
_RE_STRING_TRIPLE_DOUBLE = '"""'
|
||||
_RE_STRING_TRIPLE_SINGLE = "'''"
|
||||
_RE_STRING_DOUBLE = '"'
|
||||
|
@ -1558,6 +1578,13 @@ match the contents of a string beginning with those quotes (not including the
|
|||
terminating quotes)"""
|
||||
|
||||
|
||||
@lazyobject
|
||||
def RE_COMPLETE_STRING():
|
||||
ptrn = ('^' + _RE_STRING_START + '(?P<quote>' + "|".join(_STRINGS) + ')' +
|
||||
'.*?(?P=quote)$')
|
||||
return re.compile(ptrn)
|
||||
|
||||
|
||||
def check_for_partial_string(x):
|
||||
"""Returns the starting index (inclusive), ending index (exclusive), and
|
||||
starting quote string of the most recent Python string found in the input.
|
||||
|
|
Loading…
Add table
Reference in a new issue