mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-06 09:20:57 +01:00
Merge branch 'master' of github.com:mitnk/xonsh into history-backends
This commit is contained in:
commit
fd37e37527
11 changed files with 204 additions and 37 deletions
13
news/conda-forge.rst
Normal file
13
news/conda-forge.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
**Added:** None
|
||||
|
||||
**Changed:** None
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
**Removed:** None
|
||||
|
||||
**Fixed:**
|
||||
|
||||
* Fix failure to detect an Anaconda python distribution if the python was install from the conda-forge channel.
|
||||
|
||||
**Security:** None
|
20
news/stderr.rst
Normal file
20
news/stderr.rst
Normal file
|
@ -0,0 +1,20 @@
|
|||
**Added:**
|
||||
|
||||
* New ``$XONSH_STDERR_PREFIX`` and ``$XONSH_STDERR_POSTFIX`` environment
|
||||
variables allow the user to print a prompt-like string before and after
|
||||
all stderr that is seen. For example, say that you would like stderr
|
||||
to appear on a red background, you might set
|
||||
``$XONSH_STDERR_PREFIX = "{BACKGROUND_RED}"`` and
|
||||
``$XONSH_STDERR_PREFIX = "{NO_COLOR}"``.
|
||||
* New ``xonsh.pyghooks.XonshTerminal256Formatter`` class patches
|
||||
the pygments formatter to understand xonsh color token semantics.
|
||||
|
||||
**Changed:** None
|
||||
|
||||
**Deprecated:** None
|
||||
|
||||
**Removed:** None
|
||||
|
||||
**Fixed:** None
|
||||
|
||||
**Security:** None
|
|
@ -7,7 +7,7 @@ import time
|
|||
import builtins
|
||||
|
||||
from xonsh.tools import (XonshError, print_exception, DefaultNotGiven,
|
||||
check_for_partial_string)
|
||||
check_for_partial_string, format_std_prepost)
|
||||
from xonsh.platform import HAS_PYGMENTS, ON_WINDOWS
|
||||
from xonsh.codecache import (should_use_cache, code_cache_name,
|
||||
code_cache_check, get_cache_filename,
|
||||
|
@ -28,7 +28,8 @@ class _TeeStdBuf(io.RawIOBase):
|
|||
in memory buffer.
|
||||
"""
|
||||
|
||||
def __init__(self, stdbuf, membuf, encoding=None, errors=None):
|
||||
def __init__(self, stdbuf, membuf, encoding=None, errors=None, prestd=b'',
|
||||
poststd=b''):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
|
@ -42,11 +43,17 @@ class _TeeStdBuf(io.RawIOBase):
|
|||
errors : str or None, optional
|
||||
The error form for the encoding of the stream. Only used if stdbuf
|
||||
is a text stream, rather than a binary one.
|
||||
prestd : bytes, optional
|
||||
The prefix to prepend to the standard buffer.
|
||||
poststd : bytes, optional
|
||||
The postfix to append to the standard buffer.
|
||||
"""
|
||||
self.stdbuf = stdbuf
|
||||
self.membuf = membuf
|
||||
self.encoding = encoding
|
||||
self.errors = errors
|
||||
self.prestd = prestd
|
||||
self.poststd = poststd
|
||||
self._std_is_binary = not hasattr(stdbuf, 'encoding')
|
||||
|
||||
def fileno(self):
|
||||
|
@ -71,18 +78,24 @@ class _TeeStdBuf(io.RawIOBase):
|
|||
|
||||
def write(self, b):
|
||||
"""Write bytes into both buffers."""
|
||||
std_b = b
|
||||
if self.prestd:
|
||||
std_b = self.prestd + b
|
||||
if self.poststd:
|
||||
std_b += self.poststd
|
||||
# write to stdbuf
|
||||
if self._std_is_binary:
|
||||
self.stdbuf.write(b)
|
||||
self.stdbuf.write(std_b)
|
||||
else:
|
||||
self.stdbuf.write(b.decode(encoding=self.encoding,
|
||||
errors=self.errors))
|
||||
self.stdbuf.write(std_b.decode(encoding=self.encoding,
|
||||
errors=self.errors))
|
||||
return self.membuf.write(b)
|
||||
|
||||
|
||||
class _TeeStd(io.TextIOBase):
|
||||
"""Tees a std stream into an in-memory container and the original stream."""
|
||||
|
||||
def __init__(self, name, mem):
|
||||
def __init__(self, name, mem, prestd='', poststd=''):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
|
@ -90,17 +103,26 @@ class _TeeStd(io.TextIOBase):
|
|||
The name of the buffer in the sys module, e.g. 'stdout'.
|
||||
mem : io.TextIOBase-like
|
||||
The in-memory text-based representation.
|
||||
prestd : str, optional
|
||||
The prefix to prepend to the standard stream.
|
||||
poststd : str, optional
|
||||
The postfix to append to the standard stream.
|
||||
"""
|
||||
self._name = name
|
||||
self.std = std = getattr(sys, name)
|
||||
self.mem = mem
|
||||
self.prestd = prestd
|
||||
self.poststd = poststd
|
||||
preb = prestd.encode(encoding=mem.encoding, errors=mem.errors)
|
||||
postb = poststd.encode(encoding=mem.encoding, errors=mem.errors)
|
||||
if hasattr(std, 'buffer'):
|
||||
buffer = _TeeStdBuf(std.buffer, mem.buffer)
|
||||
buffer = _TeeStdBuf(std.buffer, mem.buffer,
|
||||
prestd=preb, poststd=postb)
|
||||
else:
|
||||
# TextIO does not have buffer as part of the API, so std streams
|
||||
# may not either.
|
||||
buffer = _TeeStdBuf(std, mem.buffer, encoding=mem.encoding,
|
||||
errors=mem.errors)
|
||||
errors=mem.errors, prestd=preb, poststd=postb)
|
||||
self.buffer = buffer
|
||||
setattr(sys, name, self)
|
||||
|
||||
|
@ -135,7 +157,12 @@ class _TeeStd(io.TextIOBase):
|
|||
|
||||
def write(self, s):
|
||||
"""Writes data to the original std stream and the in-memory object."""
|
||||
self.std.write(s)
|
||||
std_s = s
|
||||
if self.prestd:
|
||||
std_s = self.prestd + std_s
|
||||
if self.poststd:
|
||||
std_s += self.poststd
|
||||
self.std.write(std_s)
|
||||
self.mem.write(s)
|
||||
|
||||
def flush(self):
|
||||
|
@ -198,7 +225,11 @@ class Tee:
|
|||
line_buffering=line_buffering,
|
||||
write_through=write_through)
|
||||
self.stdout = _TeeStd('stdout', self.memory)
|
||||
self.stderr = _TeeStd('stderr', self.memory)
|
||||
env = builtins.__xonsh_env__
|
||||
prestderr = format_std_prepost(env.get('XONSH_STDERR_PREFIX'))
|
||||
poststderr = format_std_prepost(env.get('XONSH_STDERR_POSTFIX'))
|
||||
self.stderr = _TeeStd('stderr', self.memory, prestd=prestderr,
|
||||
poststd=poststderr)
|
||||
|
||||
@property
|
||||
def line_buffering(self):
|
||||
|
@ -280,10 +311,9 @@ class BaseShell(object):
|
|||
env = builtins.__xonsh_env__
|
||||
hist = builtins.__xonsh_history__ # pylint: disable=no-member
|
||||
ts1 = None
|
||||
store_stdout = env.get('XONSH_STORE_STDOUT') # pylint: disable=no-member
|
||||
enc = env.get('XONSH_ENCODING')
|
||||
err = env.get('XONSH_ENCODING_ERRORS')
|
||||
tee = Tee(encoding=enc, errors=err) if store_stdout else io.StringIO()
|
||||
tee = Tee(encoding=enc, errors=err)
|
||||
try:
|
||||
ts0 = time.time()
|
||||
run_compiled_code(code, self.ctx, None, 'single')
|
||||
|
@ -307,10 +337,10 @@ class BaseShell(object):
|
|||
return True
|
||||
|
||||
def _append_history(self, tee_out=None, **info):
|
||||
"""
|
||||
Append information about the command to the history.
|
||||
"""Append information about the command to the history.
|
||||
|
||||
(Also handles on_postcommand because this is the place where all the information is available)
|
||||
This also handles on_postcommand because this is the place where all the
|
||||
information is available.
|
||||
"""
|
||||
hist = builtins.__xonsh_history__ # pylint: disable=no-member
|
||||
if hist is None:
|
||||
|
@ -339,11 +369,11 @@ class BaseShell(object):
|
|||
"""Check if the cwd changed out from under us"""
|
||||
cwd = os.getcwd()
|
||||
if cwd != builtins.__xonsh_env__.get('PWD'):
|
||||
old = builtins.__xonsh_env__.get('PWD') # working directory changed without updating $PWD
|
||||
builtins.__xonsh_env__['PWD'] = cwd # track it now
|
||||
old = builtins.__xonsh_env__.get('PWD') # working directory changed without updating $PWD
|
||||
builtins.__xonsh_env__['PWD'] = cwd # track it now
|
||||
if old is not None:
|
||||
builtins.__xonsh_env__['OLDPWD'] = old # and update $OLDPWD like dirstack.
|
||||
events.on_chdir.fire(old, cwd) # fire event after cwd actually changed.
|
||||
builtins.__xonsh_env__['OLDPWD'] = old # and update $OLDPWD like dirstack.
|
||||
events.on_chdir.fire(old, cwd) # fire event after cwd actually changed.
|
||||
|
||||
def push(self, line):
|
||||
"""Pushes a line onto the buffer and compiles the code in a way that
|
||||
|
|
|
@ -159,6 +159,8 @@ def DEFAULT_ENSURERS():
|
|||
'XONSH_LOGIN': (is_bool, to_bool, bool_to_str),
|
||||
'XONSH_PROC_FREQUENCY': (is_float, float, str),
|
||||
'XONSH_SHOW_TRACEBACK': (is_bool, to_bool, bool_to_str),
|
||||
'XONSH_STDERR_PREFIX': (is_string, ensure_string, ensure_string),
|
||||
'XONSH_STDERR_POSTFIX': (is_string, ensure_string, ensure_string),
|
||||
'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),
|
||||
|
@ -302,6 +304,8 @@ def DEFAULT_VALUES():
|
|||
'XONSH_LOGIN': False,
|
||||
'XONSH_PROC_FREQUENCY': 1e-4,
|
||||
'XONSH_SHOW_TRACEBACK': False,
|
||||
'XONSH_STDERR_PREFIX': '',
|
||||
'XONSH_STDERR_POSTFIX': '',
|
||||
'XONSH_STORE_STDIN': False,
|
||||
'XONSH_STORE_STDOUT': False,
|
||||
'XONSH_TRACEBACK_LOGFILE': None,
|
||||
|
@ -670,6 +674,18 @@ def DEFAULT_DOCS():
|
|||
"When running a xonsh script, this variable contains the absolute path "
|
||||
"to the currently executing script's file.",
|
||||
configurable=False),
|
||||
'XONSH_STDERR_PREFIX': VarDocs(
|
||||
'A format string, using the same keys and colors as ``$PROMPT``, that '
|
||||
'is prepended whenever stderr is displayed. This may be used in '
|
||||
'conjunction with ``$XONSH_STDERR_POSTFIX`` to close out the block.'
|
||||
'For example, to have stderr appear on a red background, the '
|
||||
'prefix & postfix pair would be "{BACKGROUND_RED}" & "{NO_COLOR}".'),
|
||||
'XONSH_STDERR_POSTFIX': VarDocs(
|
||||
'A format string, using the same keys and colors as ``$PROMPT``, that '
|
||||
'is appended whenever stderr is displayed. This may be used in '
|
||||
'conjunction with ``$XONSH_STDERR_PREFIX`` to start the block.'
|
||||
'For example, to have stderr appear on a red background, the '
|
||||
'prefix & postfix pair would be "{BACKGROUND_RED}" & "{NO_COLOR}".'),
|
||||
'XONSH_STORE_STDIN': VarDocs(
|
||||
'Whether or not to store the stdin that is supplied to the '
|
||||
'``!()`` and ``![]`` operators.'),
|
||||
|
|
|
@ -67,3 +67,8 @@ def winutils():
|
|||
else:
|
||||
m = None
|
||||
return m
|
||||
|
||||
|
||||
@lazyobject
|
||||
def terminal256():
|
||||
return importlib.import_module('pygments.formatters.terminal256')
|
||||
|
|
|
@ -62,7 +62,7 @@ ON_BSD = LazyBool(lambda: ON_FREEBSD or ON_NETBSD,
|
|||
PYTHON_VERSION_INFO = sys.version_info[:3]
|
||||
""" Version of Python interpreter as three-value tuple. """
|
||||
ON_ANACONDA = LazyBool(
|
||||
lambda: any(s in sys.version for s in {'Anaconda', 'Continuum'}),
|
||||
lambda: any(s in sys.version for s in {'Anaconda', 'Continuum', 'conda-forge'}),
|
||||
globals(), 'ON_ANACONDA')
|
||||
""" ``True`` if executed in an Anaconda instance, else ``False``. """
|
||||
CAN_RESIZE_WINDOW = LazyBool(lambda: hasattr(signal, 'SIGWINCH'),
|
||||
|
|
|
@ -26,7 +26,7 @@ import collections.abc as cabc
|
|||
from xonsh.platform import ON_WINDOWS, ON_POSIX, CAN_RESIZE_WINDOW
|
||||
from xonsh.tools import (redirect_stdout, redirect_stderr, print_exception,
|
||||
XonshCalledProcessError, findfirst, on_main_thread,
|
||||
XonshError)
|
||||
XonshError, format_std_prepost)
|
||||
from xonsh.lazyasd import lazyobject, LazyObject
|
||||
from xonsh.jobs import wait_for_active_job
|
||||
from xonsh.lazyimps import fcntl, termios, _winapi, msvcrt, winutils
|
||||
|
@ -1681,6 +1681,7 @@ class CommandPipeline:
|
|||
self.input = self._output = self.errors = self.endtime = None
|
||||
self._closed_handle_cache = {}
|
||||
self.lines = []
|
||||
self._stderr_prefix = self._stderr_postfix = None
|
||||
|
||||
def __repr__(self):
|
||||
s = self.__class__.__name__ + '('
|
||||
|
@ -1851,6 +1852,10 @@ class CommandPipeline:
|
|||
enc = env.get('XONSH_ENCODING')
|
||||
err = env.get('XONSH_ENCODING_ERRORS')
|
||||
b = b''.join(lines)
|
||||
if self.stderr_prefix:
|
||||
b = self.stderr_prefix + b
|
||||
if self.stderr_postfix:
|
||||
b += self.stderr_postfix
|
||||
stderr_has_buffer = hasattr(sys.stderr, 'buffer')
|
||||
# write bytes to std stream
|
||||
if stderr_has_buffer:
|
||||
|
@ -2102,6 +2107,32 @@ class CommandPipeline:
|
|||
"""The resolve and executed command."""
|
||||
return self.spec.cmd
|
||||
|
||||
@property
|
||||
def stderr_prefix(self):
|
||||
"""Prefix to print in front of stderr, as bytes."""
|
||||
p = self._stderr_prefix
|
||||
if p is None:
|
||||
env = builtins.__xonsh_env__
|
||||
t = env.get('XONSH_STDERR_PREFIX')
|
||||
s = format_std_prepost(t, env=env)
|
||||
p = s.encode(encoding=env.get('XONSH_ENCODING'),
|
||||
errors=env.get('XONSH_ENCODING_ERRORS'))
|
||||
self._stderr_prefix = p
|
||||
return p
|
||||
|
||||
@property
|
||||
def stderr_postfix(self):
|
||||
"""Postfix to print after stderr, as bytes."""
|
||||
p = self._stderr_postfix
|
||||
if p is None:
|
||||
env = builtins.__xonsh_env__
|
||||
t = env.get('XONSH_STDERR_POSTFIX')
|
||||
s = format_std_prepost(t, env=env)
|
||||
p = s.encode(encoding=env.get('XONSH_ENCODING'),
|
||||
errors=env.get('XONSH_ENCODING_ERRORS'))
|
||||
self._stderr_postfix = p
|
||||
return p
|
||||
|
||||
|
||||
class HiddenCommandPipeline(CommandPipeline):
|
||||
def __repr__(self):
|
||||
|
|
|
@ -8,13 +8,14 @@ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
|||
from prompt_toolkit.layout.lexers import PygmentsLexer
|
||||
from prompt_toolkit.shortcuts import print_tokens
|
||||
from prompt_toolkit.styles import PygmentsStyle
|
||||
import pygments
|
||||
from pygments.styles import get_all_styles
|
||||
from pygments.token import Token
|
||||
|
||||
from xonsh.base_shell import BaseShell
|
||||
from xonsh.tools import print_exception
|
||||
from xonsh.pyghooks import (XonshLexer, partial_color_tokenize,
|
||||
xonsh_style_proxy)
|
||||
xonsh_style_proxy, XonshTerminal256Formatter)
|
||||
from xonsh.ptk.completer import PromptToolkitCompleter
|
||||
from xonsh.ptk.history import PromptToolkitHistory
|
||||
from xonsh.ptk.key_bindings import load_xonsh_bindings
|
||||
|
@ -205,11 +206,21 @@ class PromptToolkitShell(BaseShell):
|
|||
toks.append((Token, ' ')) # final space
|
||||
return toks
|
||||
|
||||
def format_color(self, string, **kwargs):
|
||||
def format_color(self, string, hide=False, force_string=False, **kwargs):
|
||||
"""Formats a color string using Pygments. This, therefore, returns
|
||||
a list of (Token, str) tuples.
|
||||
a list of (Token, str) tuples. If force_string is set to true, though,
|
||||
this will return a color fomtatted string.
|
||||
"""
|
||||
return partial_color_tokenize(string)
|
||||
tokens = partial_color_tokenize(string)
|
||||
if force_string:
|
||||
env = builtins.__xonsh_env__
|
||||
self.styler.style_name = env.get('XONSH_COLOR_STYLE')
|
||||
proxy_style = xonsh_style_proxy(self.styler)
|
||||
formatter = XonshTerminal256Formatter(style=proxy_style)
|
||||
s = pygments.format(tokens, formatter)
|
||||
return s
|
||||
else:
|
||||
return tokens
|
||||
|
||||
def print_color(self, string, end='\n', **kwargs):
|
||||
"""Prints a color string using prompt-toolkit color management."""
|
||||
|
|
|
@ -21,9 +21,10 @@ from pygments.styles import get_style_by_name
|
|||
import pygments.util
|
||||
|
||||
from xonsh.commands_cache import CommandsCache
|
||||
from xonsh.lazyasd import LazyObject, LazyDict
|
||||
from xonsh.lazyasd import LazyObject, LazyDict, lazyobject
|
||||
from xonsh.tools import (ON_WINDOWS, intensify_colors_for_cmd_exe,
|
||||
expand_gray_colors_for_cmd_exe)
|
||||
from xonsh.lazyimps import terminal256
|
||||
|
||||
load_module_in_background('pkg_resources', debug='XONSH_DEBUG',
|
||||
replacements={'pygments.plugin': 'pkg_resources'})
|
||||
|
@ -1389,3 +1390,27 @@ del (_algol_style, _algol_nu_style, _autumn_style, _borland_style, _bw_style,
|
|||
_murphy_style, _native_style, _paraiso_dark_style, _paraiso_light_style,
|
||||
_pastie_style, _perldoc_style, _rrt_style, _tango_style, _trac_style,
|
||||
_vim_style, _vs_style, _xcode_style)
|
||||
|
||||
|
||||
#
|
||||
# Formatter
|
||||
#
|
||||
|
||||
@lazyobject
|
||||
def XonshTerminal256Formatter():
|
||||
class XonshTerminal256FormatterProxy(terminal256.Terminal256Formatter):
|
||||
"""Proxy class for xonsh terminal256 formatting that understands.
|
||||
xonsh color tokens.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# just keep the opening token for colors.
|
||||
color_names = set(map(str, Color.subtypes))
|
||||
for name, (opener, closer) in self.style_string.items():
|
||||
if name in color_names:
|
||||
self.style_string[name] = (opener, '')
|
||||
# special case NO_COLOR, because it is special.
|
||||
self.style_string['Token.Color.NO_COLOR'] = ('\x1b[39m', '')
|
||||
|
||||
return XonshTerminal256FormatterProxy
|
||||
|
|
|
@ -29,10 +29,6 @@ from xonsh.tools import print_exception, check_for_partial_string
|
|||
from xonsh.platform import ON_WINDOWS, ON_CYGWIN, ON_DARWIN
|
||||
from xonsh.lazyimps import pygments, pyghooks
|
||||
|
||||
terminal256 = LazyObject(
|
||||
lambda: importlib.import_module('pygments.formatters.terminal256'),
|
||||
globals(), 'terminal')
|
||||
|
||||
readline = None
|
||||
RL_COMPLETION_SUPPRESS_APPEND = RL_LIB = RL_STATE = None
|
||||
RL_CAN_RESIZE = False
|
||||
|
@ -432,13 +428,13 @@ class ReadlineShell(BaseShell, cmd.Cmd):
|
|||
self.settitle()
|
||||
return p
|
||||
|
||||
def format_color(self, string, hide=False, **kwargs):
|
||||
"""Readline implementation of color formatting. This usesg ANSI color
|
||||
def format_color(self, string, hide=False, force_string=False, **kwargs):
|
||||
"""Readline implementation of color formatting. This usess ANSI color
|
||||
codes.
|
||||
"""
|
||||
hide = hide if self._force_hide is None else self._force_hide
|
||||
return ansi_partial_color_format(string, hide=hide,
|
||||
style=builtins.__xonsh_env__.get('XONSH_COLOR_STYLE'))
|
||||
style = builtins.__xonsh_env__.get('XONSH_COLOR_STYLE')
|
||||
return ansi_partial_color_format(string, hide=hide, style=style)
|
||||
|
||||
def print_color(self, string, hide=False, **kwargs):
|
||||
if isinstance(string, str):
|
||||
|
@ -448,7 +444,7 @@ class ReadlineShell(BaseShell, cmd.Cmd):
|
|||
env = builtins.__xonsh_env__
|
||||
self.styler.style_name = env.get('XONSH_COLOR_STYLE')
|
||||
style_proxy = pyghooks.xonsh_style_proxy(self.styler)
|
||||
formatter = terminal256.Terminal256Formatter(style=style_proxy)
|
||||
formatter = pyghooks.XonshTerminal256Formatter(style=style_proxy)
|
||||
s = pygments.format(string, formatter).rstrip()
|
||||
print(s, **kwargs)
|
||||
|
||||
|
|
|
@ -1413,6 +1413,27 @@ def intensify_colors_on_win_setter(enable):
|
|||
return enable
|
||||
|
||||
|
||||
def format_std_prepost(template, env=None):
|
||||
"""Formats a template prefix/postfix string for a standard buffer.
|
||||
Returns a string suitable for prepending or appending.
|
||||
"""
|
||||
if not template:
|
||||
return ''
|
||||
env = builtins.__xonsh_env__ if env is None else env
|
||||
shell = builtins.__xonsh_shell__.shell
|
||||
try:
|
||||
s = shell.prompt_formatter(template)
|
||||
except Exception:
|
||||
print_exception()
|
||||
# \001\002 is there to fool pygments into not returning an empty string
|
||||
# for potentially empty input. This happend when the template is just a
|
||||
# color code with no visible text.
|
||||
invis = '\001\002'
|
||||
s = shell.format_color(invis + s + invis, force_string=True)
|
||||
s = s.replace(invis, '')
|
||||
return s
|
||||
|
||||
|
||||
_RE_STRING_START = "[bBrRuU]*"
|
||||
_RE_STRING_TRIPLE_DOUBLE = '"""'
|
||||
_RE_STRING_TRIPLE_SINGLE = "'''"
|
||||
|
@ -1446,8 +1467,7 @@ terminating quotes)"""
|
|||
|
||||
|
||||
def check_for_partial_string(x):
|
||||
"""
|
||||
Returns the starting index (inclusive), ending index (exclusive), and
|
||||
"""Returns the starting index (inclusive), ending index (exclusive), and
|
||||
starting quote string of the most recent Python string found in the input.
|
||||
|
||||
check_for_partial_string(x) -> (startix, endix, quote)
|
||||
|
|
Loading…
Add table
Reference in a new issue