简体   繁体   中英

Can i run a Python file just like I'm typing the content in interactive mode?

For example I have a test.py :

s='123'
print(s)

I'd like this output, just like I manually type them in python :

>>> s='123'
>>> print(s)
123

But I want to run the file from CLI. python test.py and python -i test.py are not showing like that, so are ipython test.py and ipython -i test.py .

Save the following in a file called tracer.py :

import sys

class Tracer(object):
    def __init__(self):
        self._filecache = {'<string>' : open(sys.argv[1], 'r').readlines() or '\n'}
        self._linecache = {'<string>' : 0}

    def accept(self, fn):
        if fn != "<string>": # from exec
            return False
        return True

    def trace(self, frame, event, arg):
        fn = frame.f_code.co_filename
        if not self.accept(fn):
            return self.trace

        if fn not in self._filecache:
          # wait until importing of the module is done to minimize pollution
            f = frame.f_back
            while f is not None:
                try:
                    if 'import' in _filecache[f.f_code.co_filename][f.f_lineno]:
                        return self.trace
                except Exception:
                     pass
                f = f.f_back
            del f

          # import is done, and we're back, accept this file from this point on
            self._filecache[fn] = open(fn, 'r').readlines() or '\n'
            self._linecache[fn] = sys.maxsize

        lno = frame.f_lineno

        ncur = self._linecache[fn]
        buf = self._filecache[fn]

        if event == 'line':
            for i in range(ncur, lno):
                ncur = self._oneline(i, buf)

            self._linecache[fn] = max(ncur, lno)

        elif event == 'return':
            if lno <= ncur:
                fln = frame.f_code.co_firstlineno - 1
                self._oneline(fln, None)
        return self.trace

    def _oneline(self, lineno, buf):
        print('>>> ', end='')

      # simple eol case
        if not buf or not buf[lineno]:
            print()
            return

      # in general, an interpreter "line" may be longer than a file line
        line = buf[lineno].rstrip()
        haseol = False
        while line and (line[-1] in ('(', '\\', ':') or line[0] in (' ', '\t')):
         # this line appears to have a continuation ...
            try:
             # output traced line
                print(line)

             # output continued line
                lineno += 1
                print('... ', end='')
                line = buf[lineno].rstrip()
            except IndexError:
             # shouldn't happen; but must mean that the diagnosis above is
             # wrong and that there is no continuation, keep silent
                break
        else:
            print(line)
            haseol = True

        if not haseol:
            print()

        return lineno

sys.settrace(Tracer().trace)
exec(open(sys.argv[1]).read())
sys.settrace(sys._getframe(0).f_trace)

store the code you want to trace in its own file. Eg your sample code, say test.py :

s = '123'
print(s)

and run it as follows:

$ python3 tracer.py test.py

which produces the desired:

>>> s = '123'
>>> print(s)
123
>>>

I haven't tested it in anger, so there may be corner cases. Nevertheless, this should get you underway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM