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