1'''
2Entry point module to start the interactive console.
3'''
4from _pydev_imps._pydev_saved_modules import thread
5from _pydevd_bundle.pydevd_constants import IS_JYTHON, dict_iter_items
6start_new_thread = thread.start_new_thread
7
8try:
9    from code import InteractiveConsole
10except ImportError:
11    from _pydevd_bundle.pydevconsole_code_for_ironpython import InteractiveConsole
12
13from code import compile_command
14from code import InteractiveInterpreter
15
16import os
17import sys
18
19from _pydev_imps._pydev_saved_modules import threading
20from _pydevd_bundle.pydevd_constants import INTERACTIVE_MODE_AVAILABLE, dict_keys
21
22import traceback
23from _pydev_bundle import pydev_log
24
25from _pydevd_bundle import pydevd_vars, pydevd_save_locals
26
27from _pydev_bundle.pydev_imports import Exec, _queue
28
29try:
30    import __builtin__
31except:
32    import builtins as __builtin__  # @UnresolvedImport
33
34from _pydev_bundle.pydev_console_utils import BaseInterpreterInterface, BaseStdIn
35from _pydev_bundle.pydev_console_utils import CodeFragment
36
37IS_PYTHON_3_ONWARDS = sys.version_info[0] >= 3
38IS_PY24 = sys.version_info[0] == 2 and sys.version_info[1] == 4
39
40
41class Command:
42
43    def __init__(self, interpreter, code_fragment):
44        """
45        :type code_fragment: CodeFragment
46        :type interpreter: InteractiveConsole
47        """
48        self.interpreter = interpreter
49        self.code_fragment = code_fragment
50        self.more = None
51
52    def symbol_for_fragment(code_fragment):
53        if code_fragment.is_single_line:
54            symbol = 'single'
55        else:
56            if IS_JYTHON:
57                symbol = 'single'  # Jython doesn't support exec
58            else:
59                symbol = 'exec'
60        return symbol
61
62    symbol_for_fragment = staticmethod(symbol_for_fragment)
63
64    def run(self):
65        text = self.code_fragment.text
66        symbol = self.symbol_for_fragment(self.code_fragment)
67
68        self.more = self.interpreter.runsource(text, '<input>', symbol)
69
70
71try:
72    try:
73        execfile  # Not in Py3k
74    except NameError:
75        from _pydev_bundle.pydev_imports import execfile
76
77        __builtin__.execfile = execfile
78except:
79    pass
80
81# Pull in runfile, the interface to UMD that wraps execfile
82from _pydev_bundle.pydev_umd import runfile, _set_globals_function
83if sys.version_info[0] >= 3:
84    import builtins  # @UnresolvedImport
85    builtins.runfile = runfile
86else:
87    import __builtin__
88    __builtin__.runfile = runfile
89
90
91#=======================================================================================================================
92# InterpreterInterface
93#=======================================================================================================================
94class InterpreterInterface(BaseInterpreterInterface):
95    '''
96        The methods in this class should be registered in the xml-rpc server.
97    '''
98
99    def __init__(self, host, client_port, mainThread, connect_status_queue=None):
100        BaseInterpreterInterface.__init__(self, mainThread, connect_status_queue)
101        self.client_port = client_port
102        self.host = host
103        self.namespace = {}
104        self.interpreter = InteractiveConsole(self.namespace)
105        self._input_error_printed = False
106
107    def do_add_exec(self, codeFragment):
108        command = Command(self.interpreter, codeFragment)
109        command.run()
110        return command.more
111
112    def get_namespace(self):
113        return self.namespace
114
115    def getCompletions(self, text, act_tok):
116        try:
117            from _pydev_bundle._pydev_completer import Completer
118
119            completer = Completer(self.namespace, None)
120            return completer.complete(act_tok)
121        except:
122            pydev_log.exception()
123            return []
124
125    def close(self):
126        sys.exit(0)
127
128    def get_greeting_msg(self):
129        return 'PyDev console: starting.\n'
130
131
132class _ProcessExecQueueHelper:
133    _debug_hook = None
134    _return_control_osc = False
135
136
137def set_debug_hook(debug_hook):
138    _ProcessExecQueueHelper._debug_hook = debug_hook
139
140
141def activate_mpl_if_already_imported(interpreter):
142    if interpreter.mpl_modules_for_patching:
143        for module in dict_keys(interpreter.mpl_modules_for_patching):
144            if module in sys.modules:
145                activate_function = interpreter.mpl_modules_for_patching.pop(module)
146                activate_function()
147
148
149def init_set_return_control_back(interpreter):
150    from pydev_ipython.inputhook import set_return_control_callback
151
152    def return_control():
153        ''' A function that the inputhooks can call (via inputhook.stdin_ready()) to find
154            out if they should cede control and return '''
155        if _ProcessExecQueueHelper._debug_hook:
156            # Some of the input hooks check return control without doing
157            # a single operation, so we don't return True on every
158            # call when the debug hook is in place to allow the GUI to run
159            # XXX: Eventually the inputhook code will have diverged enough
160            # from the IPython source that it will be worthwhile rewriting
161            # it rather than pretending to maintain the old API
162            _ProcessExecQueueHelper._return_control_osc = not _ProcessExecQueueHelper._return_control_osc
163            if _ProcessExecQueueHelper._return_control_osc:
164                return True
165
166        if not interpreter.exec_queue.empty():
167            return True
168        return False
169
170    set_return_control_callback(return_control)
171
172
173def init_mpl_in_console(interpreter):
174    init_set_return_control_back(interpreter)
175
176    if not INTERACTIVE_MODE_AVAILABLE:
177        return
178
179    activate_mpl_if_already_imported(interpreter)
180    from _pydev_bundle.pydev_import_hook import import_hook_manager
181    for mod in dict_keys(interpreter.mpl_modules_for_patching):
182        import_hook_manager.add_module_name(mod, interpreter.mpl_modules_for_patching.pop(mod))
183
184
185if sys.platform != 'win32':
186
187    if not hasattr(os, 'kill'):  # Jython may not have it.
188
189        def pid_exists(pid):
190            return True
191
192    else:
193
194        def pid_exists(pid):
195            # Note that this function in the face of errors will conservatively consider that
196            # the pid is still running (because we'll exit the current process when it's
197            # no longer running, so, we need to be 100% sure it actually exited).
198
199            import errno
200            if pid == 0:
201                # According to "man 2 kill" PID 0 has a special meaning:
202                # it refers to <<every process in the process group of the
203                # calling process>> so we don't want to go any further.
204                # If we get here it means this UNIX platform *does* have
205                # a process with id 0.
206                return True
207            try:
208                os.kill(pid, 0)
209            except OSError as err:
210                if err.errno == errno.ESRCH:
211                    # ESRCH == No such process
212                    return False
213                elif err.errno == errno.EPERM:
214                    # EPERM clearly means there's a process to deny access to
215                    return True
216                else:
217                    # According to "man 2 kill" possible error values are
218                    # (EINVAL, EPERM, ESRCH) therefore we should never get
219                    # here. If we do, although it's an error, consider it
220                    # exists (see first comment in this function).
221                    return True
222            else:
223                return True
224
225else:
226
227    def pid_exists(pid):
228        # Note that this function in the face of errors will conservatively consider that
229        # the pid is still running (because we'll exit the current process when it's
230        # no longer running, so, we need to be 100% sure it actually exited).
231        import ctypes
232        kernel32 = ctypes.windll.kernel32
233
234        PROCESS_QUERY_INFORMATION = 0x0400
235        PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
236        ERROR_INVALID_PARAMETER = 0x57
237        STILL_ACTIVE = 259
238
239        process = kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, 0, pid)
240        if not process:
241            err = kernel32.GetLastError()
242            if err == ERROR_INVALID_PARAMETER:
243                # Means it doesn't exist (pid parameter is wrong).
244                return False
245
246            # There was some unexpected error (such as access denied), so
247            # consider it exists (although it could be something else, but we don't want
248            # to raise any errors -- so, just consider it exists).
249            return True
250
251        try:
252            zero = ctypes.c_int(0)
253            exit_code = ctypes.pointer(zero)
254
255            exit_code_suceeded = kernel32.GetExitCodeProcess(process, exit_code)
256            if not exit_code_suceeded:
257                # There was some unexpected error (such as access denied), so
258                # consider it exists (although it could be something else, but we don't want
259                # to raise any errors -- so, just consider it exists).
260                return True
261
262            elif bool(exit_code.contents.value) and int(exit_code.contents.value) != STILL_ACTIVE:
263                return False
264        finally:
265            kernel32.CloseHandle(process)
266
267        return True
268
269
270def process_exec_queue(interpreter):
271    init_mpl_in_console(interpreter)
272    from pydev_ipython.inputhook import get_inputhook
273    try:
274        kill_if_pid_not_alive = int(os.environ.get('PYDEV_ECLIPSE_PID', '-1'))
275    except:
276        kill_if_pid_not_alive = -1
277
278    while 1:
279        if kill_if_pid_not_alive != -1:
280            if not pid_exists(kill_if_pid_not_alive):
281                exit()
282
283        # Running the request may have changed the inputhook in use
284        inputhook = get_inputhook()
285
286        if _ProcessExecQueueHelper._debug_hook:
287            _ProcessExecQueueHelper._debug_hook()
288
289        if inputhook:
290            try:
291                # Note: it'll block here until return_control returns True.
292                inputhook()
293            except:
294                pydev_log.exception()
295        try:
296            try:
297                code_fragment = interpreter.exec_queue.get(block=True, timeout=1 / 20.)  # 20 calls/second
298            except _queue.Empty:
299                continue
300
301            if callable(code_fragment):
302                # It can be a callable (i.e.: something that must run in the main
303                # thread can be put in the queue for later execution).
304                code_fragment()
305            else:
306                more = interpreter.add_exec(code_fragment)
307        except KeyboardInterrupt:
308            interpreter.buffer = None
309            continue
310        except SystemExit:
311            raise
312        except:
313            pydev_log.exception('Error processing queue on pydevconsole.')
314            exit()
315
316
317if 'IPYTHONENABLE' in os.environ:
318    IPYTHON = os.environ['IPYTHONENABLE'] == 'True'
319else:
320    # By default, don't use IPython because occasionally changes
321    # in IPython break pydevd.
322    IPYTHON = False
323
324try:
325    try:
326        exitfunc = sys.exitfunc
327    except AttributeError:
328        exitfunc = None
329
330    if IPYTHON:
331        from _pydev_bundle.pydev_ipython_console import InterpreterInterface
332        if exitfunc is not None:
333            sys.exitfunc = exitfunc
334        else:
335            try:
336                delattr(sys, 'exitfunc')
337            except:
338                pass
339except:
340    IPYTHON = False
341    pass
342
343
344#=======================================================================================================================
345# _DoExit
346#=======================================================================================================================
347def do_exit(*args):
348    '''
349        We have to override the exit because calling sys.exit will only actually exit the main thread,
350        and as we're in a Xml-rpc server, that won't work.
351    '''
352
353    try:
354        import java.lang.System
355
356        java.lang.System.exit(1)
357    except ImportError:
358        if len(args) == 1:
359            os._exit(args[0])
360        else:
361            os._exit(0)
362
363
364#=======================================================================================================================
365# start_console_server
366#=======================================================================================================================
367def start_console_server(host, port, interpreter):
368    try:
369        if port == 0:
370            host = ''
371
372        # I.e.: supporting the internal Jython version in PyDev to create a Jython interactive console inside Eclipse.
373        from _pydev_bundle.pydev_imports import SimpleXMLRPCServer as XMLRPCServer  # @Reimport
374
375        try:
376            if IS_PY24:
377                server = XMLRPCServer((host, port), logRequests=False)
378            else:
379                server = XMLRPCServer((host, port), logRequests=False, allow_none=True)
380
381        except:
382            sys.stderr.write('Error starting server with host: "%s", port: "%s", client_port: "%s"\n' % (host, port, interpreter.client_port))
383            sys.stderr.flush()
384            raise
385
386        # Tell UMD the proper default namespace
387        _set_globals_function(interpreter.get_namespace)
388
389        server.register_function(interpreter.execLine)
390        server.register_function(interpreter.execMultipleLines)
391        server.register_function(interpreter.getCompletions)
392        server.register_function(interpreter.getFrame)
393        server.register_function(interpreter.getVariable)
394        server.register_function(interpreter.changeVariable)
395        server.register_function(interpreter.getDescription)
396        server.register_function(interpreter.close)
397        server.register_function(interpreter.interrupt)
398        server.register_function(interpreter.handshake)
399        server.register_function(interpreter.connectToDebugger)
400        server.register_function(interpreter.hello)
401        server.register_function(interpreter.getArray)
402        server.register_function(interpreter.evaluate)
403        server.register_function(interpreter.ShowConsole)
404        server.register_function(interpreter.loadFullValue)
405
406        # Functions for GUI main loop integration
407        server.register_function(interpreter.enableGui)
408
409        if port == 0:
410            (h, port) = server.socket.getsockname()
411
412            print(port)
413            print(interpreter.client_port)
414
415        while True:
416            try:
417                server.serve_forever()
418            except:
419                # Ugly code to be py2/3 compatible
420                # https://sw-brainwy.rhcloud.com/tracker/PyDev/534:
421                # Unhandled "interrupted system call" error in the pydevconsol.py
422                e = sys.exc_info()[1]
423                retry = False
424                try:
425                    retry = e.args[0] == 4  # errno.EINTR
426                except:
427                    pass
428                if not retry:
429                    raise
430                    # Otherwise, keep on going
431        return server
432    except:
433        pydev_log.exception()
434        # Notify about error to avoid long waiting
435        connection_queue = interpreter.get_connect_status_queue()
436        if connection_queue is not None:
437            connection_queue.put(False)
438
439
440def start_server(host, port, client_port):
441    # replace exit (see comments on method)
442    # note that this does not work in jython!!! (sys method can't be replaced).
443    sys.exit = do_exit
444
445    interpreter = InterpreterInterface(host, client_port, threading.currentThread())
446
447    start_new_thread(start_console_server, (host, port, interpreter))
448
449    process_exec_queue(interpreter)
450
451
452def get_ipython_hidden_vars():
453    if IPYTHON and hasattr(__builtin__, 'interpreter'):
454        interpreter = get_interpreter()
455        return interpreter.get_ipython_hidden_vars_dict()
456
457
458def get_interpreter():
459    try:
460        interpreterInterface = getattr(__builtin__, 'interpreter')
461    except AttributeError:
462        interpreterInterface = InterpreterInterface(None, None, threading.currentThread())
463        __builtin__.interpreter = interpreterInterface
464        sys.stderr.write(interpreterInterface.get_greeting_msg())
465        sys.stderr.flush()
466
467    return interpreterInterface
468
469
470def get_completions(text, token, globals, locals):
471    interpreterInterface = get_interpreter()
472
473    interpreterInterface.interpreter.update(globals, locals)
474
475    return interpreterInterface.getCompletions(text, token)
476
477#===============================================================================
478# Debugger integration
479#===============================================================================
480
481
482def exec_code(code, globals, locals, debugger):
483    interpreterInterface = get_interpreter()
484    interpreterInterface.interpreter.update(globals, locals)
485
486    res = interpreterInterface.need_more(code)
487
488    if res:
489        return True
490
491    interpreterInterface.add_exec(code, debugger)
492
493    return False
494
495
496class ConsoleWriter(InteractiveInterpreter):
497    skip = 0
498
499    def __init__(self, locals=None):
500        InteractiveInterpreter.__init__(self, locals)
501
502    def write(self, data):
503        # if (data.find("global_vars") == -1 and data.find("pydevd") == -1):
504        if self.skip > 0:
505            self.skip -= 1
506        else:
507            if data == "Traceback (most recent call last):\n":
508                self.skip = 1
509            sys.stderr.write(data)
510
511    def showsyntaxerror(self, filename=None):
512        """Display the syntax error that just occurred."""
513        # Override for avoid using sys.excepthook PY-12600
514        type, value, tb = sys.exc_info()
515        sys.last_type = type
516        sys.last_value = value
517        sys.last_traceback = tb
518        if filename and type is SyntaxError:
519            # Work hard to stuff the correct filename in the exception
520            try:
521                msg, (dummy_filename, lineno, offset, line) = value.args
522            except ValueError:
523                # Not the format we expect; leave it alone
524                pass
525            else:
526                # Stuff in the right filename
527                value = SyntaxError(msg, (filename, lineno, offset, line))
528                sys.last_value = value
529        list = traceback.format_exception_only(type, value)
530        sys.stderr.write(''.join(list))
531
532    def showtraceback(self, *args, **kwargs):
533        """Display the exception that just occurred."""
534        # Override for avoid using sys.excepthook PY-12600
535        try:
536            type, value, tb = sys.exc_info()
537            sys.last_type = type
538            sys.last_value = value
539            sys.last_traceback = tb
540            tblist = traceback.extract_tb(tb)
541            del tblist[:1]
542            lines = traceback.format_list(tblist)
543            if lines:
544                lines.insert(0, "Traceback (most recent call last):\n")
545            lines.extend(traceback.format_exception_only(type, value))
546        finally:
547            tblist = tb = None
548        sys.stderr.write(''.join(lines))
549
550
551def console_exec(thread_id, frame_id, expression, dbg):
552    """returns 'False' in case expression is partially correct
553    """
554    frame = dbg.find_frame(thread_id, frame_id)
555
556    is_multiline = expression.count('@LINE@') > 1
557    expression = str(expression.replace('@LINE@', '\n'))
558
559    # Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329
560    # (Names not resolved in generator expression in method)
561    # See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html
562    updated_globals = {}
563    updated_globals.update(frame.f_globals)
564    updated_globals.update(frame.f_locals)  # locals later because it has precedence over the actual globals
565
566    if IPYTHON:
567        need_more = exec_code(CodeFragment(expression), updated_globals, frame.f_locals, dbg)
568        if not need_more:
569            pydevd_save_locals.save_locals(frame)
570        return need_more
571
572    interpreter = ConsoleWriter()
573
574    if not is_multiline:
575        try:
576            code = compile_command(expression)
577        except (OverflowError, SyntaxError, ValueError):
578            # Case 1
579            interpreter.showsyntaxerror()
580            return False
581        if code is None:
582            # Case 2
583            return True
584    else:
585        code = expression
586
587    # Case 3
588
589    try:
590        Exec(code, updated_globals, frame.f_locals)
591
592    except SystemExit:
593        raise
594    except:
595        interpreter.showtraceback()
596    else:
597        pydevd_save_locals.save_locals(frame)
598    return False
599
600
601#=======================================================================================================================
602# main
603#=======================================================================================================================
604if __name__ == '__main__':
605    # Important: don't use this module directly as the __main__ module, rather, import itself as pydevconsole
606    # so that we don't get multiple pydevconsole modules if it's executed directly (otherwise we'd have multiple
607    # representations of its classes).
608    # See: https://sw-brainwy.rhcloud.com/tracker/PyDev/446:
609    # 'Variables' and 'Expressions' views stopped working when debugging interactive console
610    import pydevconsole
611    sys.stdin = pydevconsole.BaseStdIn(sys.stdin)
612    port, client_port = sys.argv[1:3]
613    from _pydev_bundle import pydev_localhost
614
615    if int(port) == 0 and int(client_port) == 0:
616        (h, p) = pydev_localhost.get_socket_name()
617
618        client_port = p
619
620    pydevconsole.start_server(pydev_localhost.get_localhost(), int(port), int(client_port))
621