Exemplo n.º 1
0
"""Tools for preparing code to be run in the REPL (removing blank lines, etc)"""

from bpython.lazyre import LazyReCompile

#TODO specifically catch IndentationErrors instead of any syntax errors

indent_empty_lines_re = LazyReCompile(r'\s*')


def indent_empty_lines(s, compiler):
    """Indents blank lines that would otherwise cause early compilation

    Only really works if starting on a new line"""
    lines = s.split('\n')
    ends_with_newline = False
    if lines and not lines[-1]:
        ends_with_newline = True
        lines.pop()
    result_lines = []

    for p_line, line, n_line in zip([''] + lines[:-1], lines,
                                    lines[1:] + ['']):
        if len(line) == 0:
            p_indent = indent_empty_lines_re.match(p_line).group()
            n_indent = indent_empty_lines_re.match(n_line).group()
            result_lines.append(min([p_indent, n_indent], key=len) + line)
        else:
            result_lines.append(line)

    return '\n'.join(result_lines) + ('\n' if ends_with_newline else '')
Exemplo n.º 2
0
    return min(len(line), cursor_offset + 1), line


@edit_keys.on(config='beginning_of_line_key')
@edit_keys.on('<HOME>')
def beginning_of_line(cursor_offset, line):
    return 0, line


@edit_keys.on(config='end_of_line_key')
@edit_keys.on('<END>')
def end_of_line(cursor_offset, line):
    return len(line), line


forward_word_re = LazyReCompile(r"\S\s")


@edit_keys.on('<Esc+f>')
@edit_keys.on('<Ctrl-RIGHT>')
@edit_keys.on('<Esc+RIGHT>')
def forward_word(cursor_offset, line):
    match = forward_word_re.search(line[cursor_offset:] + ' ')
    delta = match.end() - 1 if match else 0
    return (cursor_offset + delta, line)


def last_word_pos(string):
    """returns the start index of the last word of given string"""
    match = forward_word_re.search(string[::-1])
    index = match and len(string) - match.end() + 1
Exemplo n.º 3
0
"""Extracting and changing portions of the current line

All functions take cursor offset from the beginning of the line and the line of
Python code, and return None, or a tuple of the start index, end index, and the
word."""

from itertools import chain
from collections import namedtuple
from bpython.lazyre import LazyReCompile

current_word_re = LazyReCompile(r'[\w_][\w0-9._]*[(]?')
LinePart = namedtuple('LinePart', ['start', 'stop', 'word'])


def current_word(cursor_offset, line):
    """the object.attribute.attribute just before or under the cursor"""
    pos = cursor_offset
    matches = current_word_re.finditer(line)
    start = pos
    end = pos
    word = None
    for m in matches:
        if m.start() < pos and m.end() >= pos:
            start = m.start()
            end = m.end()
            word = m.group()
    if word is None:
        return None
    return LinePart(start, end, word)

Exemplo n.º 4
0
import inspect
import io
import keyword
import pydoc
from collections import namedtuple
from six.moves import range

from pygments.token import Token

from bpython._py3compat import PythonLexer, py3
from bpython.lazyre import LazyReCompile

if not py3:
    import types

    _name = LazyReCompile(r'[a-zA-Z_]\w*$')

ArgSpec = namedtuple('ArgSpec', ['args', 'varargs', 'varkwargs',  'defaults',
                                 'kwonly', 'kwonly_defaults', 'annotations'])

FuncProps = namedtuple('FuncProps', ['func', 'argspec', 'is_bound_method'])


class AttrCleaner(object):
    """A context manager that tries to make an object not exhibit side-effects
       on attribute lookup."""

    def __init__(self, obj):
        self.obj = obj

    def __enter__(self):
Exemplo n.º 5
0
# encoding: utf-8

"""Tools for preparing code to be run in the REPL (removing blank lines,
etc)"""

from bpython.lazyre import LazyReCompile

# TODO specifically catch IndentationErrors instead of any syntax errors


indent_empty_lines_re = LazyReCompile(r'\s*')
tabs_to_spaces_re = LazyReCompile(r'^\t+')


def indent_empty_lines(s, compiler):
    """Indents blank lines that would otherwise cause early compilation

    Only really works if starting on a new line"""
    lines = s.split('\n')
    ends_with_newline = False
    if lines and not lines[-1]:
        ends_with_newline = True
        lines.pop()
    result_lines = []

    for p_line, line, n_line in zip([''] + lines[:-1], lines,
                                    lines[1:] + ['']):
        if len(line) == 0:
            p_indent = indent_empty_lines_re.match(p_line).group()
            n_indent = indent_empty_lines_re.match(n_line).group()
            result_lines.append(min([p_indent, n_indent], key=len) + line)
Exemplo n.º 6
0
                           len(colors)]
        else:
            color = cnames[d["bg"].lower()]
        if color != "default":
            atts["bg"] = BG_COLORS[color]
    if d["bold"]:
        atts["bold"] = True
    return fmtstr(d["string"], **atts)


peel_off_string_re = LazyReCompile(
    r"""(?P<colormarker>\x01
            (?P<fg>[krgybmcwdKRGYBMCWD]?)
            (?P<bg>[krgybmcwdKRGYBMCWDI]?)?)
        (?P<bold>\x02?)
        \x03
        (?P<string>[^\x04]*)
        \x04
        (?P<rest>.*)
        """,
    re.VERBOSE | re.DOTALL,
)


def peel_off_string(s):
    m = peel_off_string_re.match(s)
    assert m, repr(s)
    d = m.groupdict()
    rest = d["rest"]
    del d["rest"]
    return d, rest
Exemplo n.º 7
0
class EvaluationError(Exception):
    """Raised if an exception occurred in safe_eval."""


def safe_eval(expr, namespace):
    """Not all that safe, just catches some errors"""
    try:
        return eval(expr, namespace)
    except (NameError, AttributeError, SyntaxError):
        # If debugging safe_eval, raise this!
        # raise
        raise EvaluationError


attr_matches_re = LazyReCompile(r"(\w+(\.\w+)*)\.(\w*)")


def attr_matches(text, namespace):
    """Taken from rlcompleter.py and bent to my will.
    """

    # Gna, Py 2.6's rlcompleter searches for __call__ inside the
    # instance instead of the type, so we monkeypatch to prevent
    # side-effects (__getattr__/__getattribute__)
    m = attr_matches_re.match(text)
    if not m:
        return []

    expr, attr = m.group(1, 3)
    if expr.isdigit():
Exemplo n.º 8
0
class AttrCompletion(BaseCompletionType):

    attr_matches_re = LazyReCompile(r"(\w+(\.\w+)*)\.(\w*)")

    def matches(self, cursor_offset, line, **kwargs):
        if 'locals_' not in kwargs:
            return None
        locals_ = kwargs['locals_']

        r = self.locate(cursor_offset, line)
        if r is None:
            return None

        if locals_ is None:
            locals_ = __main__.__dict__

        assert '.' in r.word

        for i in range(1, len(r.word) + 1):
            if r.word[-i] == '[':
                i -= 1
                break
        methodtext = r.word[-i:]
        matches = set(''.join([r.word[:-i], m])
                      for m in self.attr_matches(methodtext, locals_))

        # TODO add open paren for methods via _callable_prefix (or decide not
        # to) unless the first character is a _ filter out all attributes
        # starting with a _
        if r.word.split('.')[-1].startswith('__'):
            pass
        elif r.word.split('.')[-1].startswith('_'):
            matches = set(match for match in matches
                          if not match.split('.')[-1].startswith('__'))
        else:
            matches = set(match for match in matches
                          if not match.split('.')[-1].startswith('_'))
        return matches

    def locate(self, current_offset, line):
        return lineparts.current_dotted_attribute(current_offset, line)

    def format(self, word):
        return after_last_dot(word)

    def attr_matches(self, text, namespace):
        """Taken from rlcompleter.py and bent to my will.
        """

        # Gna, Py 2.6's rlcompleter searches for __call__ inside the
        # instance instead of the type, so we monkeypatch to prevent
        # side-effects (__getattr__/__getattribute__)
        m = self.attr_matches_re.match(text)
        if not m:
            return []

        expr, attr = m.group(1, 3)
        if expr.isdigit():
            # Special case: float literal, using attrs here will result in
            # a SyntaxError
            return []
        try:
            obj = safe_eval(expr, namespace)
        except EvaluationError:
            return []
        with inspection.AttrCleaner(obj):
            matches = self.attr_lookup(obj, expr, attr)
        return matches

    def attr_lookup(self, obj, expr, attr):
        """Second half of original attr_matches method factored out so it can
        be wrapped in a safe try/finally block in case anything bad happens to
        restore the original __getattribute__ method."""
        words = self.list_attributes(obj)
        if hasattr(obj, '__class__'):
            words.append('__class__')
            words = words + rlcompleter.get_class_members(obj.__class__)
            if not isinstance(obj.__class__, abc.ABCMeta):
                try:
                    words.remove('__abstractmethods__')
                except ValueError:
                    pass

        if not py3 and isinstance(obj, (InstanceType, ClassType)):
            # Account for the __dict__ in an old-style class.
            words.append('__dict__')

        matches = []
        n = len(attr)
        for word in words:
            if self.method_match(word, n, attr) and word != "__builtins__":
                matches.append("%s.%s" % (expr, word))
        return matches

    if py3:
        def list_attributes(self, obj):
            return dir(obj)
    else:
        def list_attributes(self, obj):
            if isinstance(obj, InstanceType):
                try:
                    return dir(obj)
                except Exception:
                    # This is a case where we can not prevent user code from
                    # running. We return a default list attributes on error
                    # instead. (#536)
                    return ['__doc__', '__module__']
            else:
                return dir(obj)
Exemplo n.º 9
0
    return min(len(line), cursor_offset + 1), line


@edit_keys.on(config="beginning_of_line_key")
@edit_keys.on("<HOME>")
def beginning_of_line(cursor_offset, line):
    return 0, line


@edit_keys.on(config="end_of_line_key")
@edit_keys.on("<END>")
def end_of_line(cursor_offset, line):
    return len(line), line


forward_word_re = LazyReCompile(r"\S\s")


@edit_keys.on("<Esc+f>")
@edit_keys.on("<Ctrl-RIGHT>")
@edit_keys.on("<Esc+RIGHT>")
def forward_word(cursor_offset, line):
    match = forward_word_re.search(line[cursor_offset:] + " ")
    delta = match.end() - 1 if match else 0
    return (cursor_offset + delta, line)


def last_word_pos(string):
    """returns the start index of the last word of given string"""
    match = forward_word_re.search(string[::-1])
    index = match and len(string) - match.end() + 1
Exemplo n.º 10
0
"""Tools for preparing code to be run in the REPL (removing blank lines,
etc)"""

from bpython.lazyre import LazyReCompile

# TODO specifically catch IndentationErrors instead of any syntax errors

indent_empty_lines_re = LazyReCompile(r"\s*")
tabs_to_spaces_re = LazyReCompile(r"^\t+")


def indent_empty_lines(s, compiler):
    """Indents blank lines that would otherwise cause early compilation

    Only really works if starting on a new line"""
    lines = s.split("\n")
    ends_with_newline = False
    if lines and not lines[-1]:
        ends_with_newline = True
        lines.pop()
    result_lines = []

    for p_line, line, n_line in zip([""] + lines[:-1], lines,
                                    lines[1:] + [""]):
        if len(line) == 0:
            p_indent = indent_empty_lines_re.match(p_line).group()
            n_indent = indent_empty_lines_re.match(n_line).group()
            result_lines.append(min([p_indent, n_indent], key=len) + line)
        else:
            result_lines.append(line)
Exemplo n.º 11
0
"""Extracting and changing portions of the current line

All functions take cursor offset from the beginning of the line and the line of
Python code, and return None, or a tuple of the start index, end index, and the
word."""
from __future__ import unicode_literals

from itertools import chain
from collections import namedtuple

from bpython.lazyre import LazyReCompile

current_word_re = LazyReCompile(r'[\w_][\w0-9._]*[(]?')
LinePart = namedtuple('LinePart', ['start', 'stop', 'word'])


def current_word(cursor_offset, line):
    """the object.attribute.attribute just before or under the cursor"""
    pos = cursor_offset
    matches = current_word_re.finditer(line)
    start = pos
    end = pos
    word = None
    for m in matches:
        if m.start() < pos and m.end() >= pos:
            start = m.start()
            end = m.end()
            word = m.group()
    if word is None:
        return None
    return LinePart(start, end, word)