File: patch_linecache.py

package info (click to toggle)
bpython 0.21-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,112 kB
  • sloc: python: 11,963; xml: 53; makefile: 6; sh: 2
file content (80 lines) | stat: -rw-r--r-- 2,681 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import linecache


class BPythonLinecache(dict):
    """Replaces the cache dict in the standard-library linecache module,
    to also remember (in an unerasable way) bpython console input."""

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.bpython_history = []

    def is_bpython_filename(self, fname):
        try:
            return fname.startswith("<bpython-input-")
        except AttributeError:
            # In case the key isn't a string
            return False

    def get_bpython_history(self, key):
        """Given a filename provided by remember_bpython_input,
        returns the associated source string."""
        try:
            idx = int(key.split("-")[2][:-1])
            return self.bpython_history[idx]
        except (IndexError, ValueError):
            raise KeyError

    def remember_bpython_input(self, source):
        """Remembers a string of source code, and returns
        a fake filename to use to retrieve it later."""
        filename = "<bpython-input-%s>" % len(self.bpython_history)
        self.bpython_history.append(
            (len(source), None, source.splitlines(True), filename)
        )
        return filename

    def __getitem__(self, key):
        if self.is_bpython_filename(key):
            return self.get_bpython_history(key)
        return super().__getitem__(key)

    def __contains__(self, key):
        if self.is_bpython_filename(key):
            try:
                self.get_bpython_history(key)
                return True
            except KeyError:
                return False
        return super().__contains__(key)

    def __delitem__(self, key):
        if not self.is_bpython_filename(key):
            return super().__delitem__(key)


def _bpython_clear_linecache():
    try:
        bpython_history = linecache.cache.bpython_history
    except AttributeError:
        bpython_history = []
    linecache.cache = BPythonLinecache()
    linecache.cache.bpython_history = bpython_history


# Monkey-patch the linecache module so that we're able
# to hold our command history there and have it persist
linecache.cache = BPythonLinecache(linecache.cache)
linecache.clearcache = _bpython_clear_linecache


def filename_for_console_input(code_string):
    """Remembers a string of source code, and returns
    a fake filename to use to retrieve it later."""
    try:
        return linecache.cache.remember_bpython_input(code_string)
    except AttributeError:
        # If someone else has patched linecache.cache, better for code to
        # simply be unavailable to inspect.getsource() than to raise
        # an exception.
        return "<input>"